diff --git a/mythtv/configure b/mythtv/configure index 31d11647096..9228929e57e 100755 --- a/mythtv/configure +++ b/mythtv/configure @@ -109,7 +109,6 @@ Advanced options (experts only): --libcec-path=HDRLOC location of directory containing cec.h [$libcec_path_default] --disable-firewire disable support for FireWire cable boxes - --disable-iptv disable support for recording RTSP/UDP/RTP streams --disable-hdhomerun disable support for HDHomeRun boxes --disable-ceton disable support for Ceton cards --disable-v4l2 disable Video4Linux support @@ -1351,7 +1350,6 @@ MYTHTV_CONFIG_LIST=' hdhomerun ceton hdpvr - iptv ivtv asi joystick_menu @@ -1777,7 +1775,6 @@ doc_deps="texi2html" audio_oss_deps_any="soundcard_h sys_soundcard_h" dvb_deps="backend" firewire_deps="backend" -iptv_deps="backend" ivtv_deps="backend v4l2" hdpvr_deps="backend v4l2" hdhomerun_deps="backend" @@ -1996,7 +1993,6 @@ enable frontend enable hdhomerun enable ceton enable hdpvr -enable iptv enable ivtv enable asi enable lamemp3 @@ -4533,7 +4529,6 @@ if enabled backend; then echo "DVB-S2 support ${fe_can_2g_modulation-no}" echo "HDHomeRun support ${hdhomerun-no}" echo "Ceton support ${ceton-no}" - echo "IPTV support ${iptv-no}" echo "ASI support ${asi-no}" fi @@ -4857,10 +4852,6 @@ if enabled firewire; then fi fi -if enabled iptv; then - append CCONFIG "using_live" -fi - if enabled mheg; then append CCONFIG "using_mheg" fi diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicHashTable.cpp b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicHashTable.cpp deleted file mode 100644 index d06c0b4d930..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicHashTable.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Hash Table implementation -// Implementation - -#include "BasicHashTable.hh" -#include "strDup.hh" - -#if defined(__WIN32__) || defined(_WIN32) -#else -#include -#endif -#include -#include - -// When there are this many entries per bucket, on average, rebuild -// the table to increase the number of buckets -#define REBUILD_MULTIPLIER 3 - -BasicHashTable::BasicHashTable(int keyType) - : fBuckets(fStaticBuckets), fNumBuckets(SMALL_HASH_TABLE_SIZE), - fNumEntries(0), fRebuildSize(SMALL_HASH_TABLE_SIZE*REBUILD_MULTIPLIER), - fDownShift(28), fMask(0x3), fKeyType(keyType) { - for (unsigned i = 0; i < SMALL_HASH_TABLE_SIZE; ++i) { - fStaticBuckets[i] = NULL; - } -} - -BasicHashTable::~BasicHashTable() { - // Free all the entries in the table: - for (unsigned i = 0; i < fNumBuckets; ++i) { - TableEntry* entry; - while ((entry = fBuckets[i]) != NULL) { - deleteEntry(i, entry); - } - } - - // Also free the bucket array, if it was dynamically allocated: - if (fBuckets != fStaticBuckets) delete[] fBuckets; -} - -void* BasicHashTable::Add(char const* key, void* value) { - void* oldValue; - unsigned index; - TableEntry* entry = lookupKey(key, index); - if (entry != NULL) { - // There's already an item with this key - oldValue = entry->value; - } else { - // There's no existing entry; create a new one: - entry = insertNewEntry(index, key); - oldValue = NULL; - } - entry->value = value; - - // If the table has become too large, rebuild it with more buckets: - if (fNumEntries >= fRebuildSize) rebuild(); - - return oldValue; -} - -Boolean BasicHashTable::Remove(char const* key) { - unsigned index; - TableEntry* entry = lookupKey(key, index); - if (entry == NULL) return False; // no such entry - - deleteEntry(index, entry); - - return True; -} - -void* BasicHashTable::Lookup(char const* key) const { - unsigned index; - TableEntry* entry = lookupKey(key, index); - if (entry == NULL) return NULL; // no such entry - - return entry->value; -} - -unsigned BasicHashTable::numEntries() const { - return fNumEntries; -} - -BasicHashTable::Iterator::Iterator(BasicHashTable& table) - : fTable(table), fNextIndex(0), fNextEntry(NULL) { -} - -void* BasicHashTable::Iterator::next(char const*& key) { - while (fNextEntry == NULL) { - if (fNextIndex >= fTable.fNumBuckets) return NULL; - - fNextEntry = fTable.fBuckets[fNextIndex++]; - } - - BasicHashTable::TableEntry* entry = fNextEntry; - fNextEntry = entry->fNext; - - key = entry->key; - return entry->value; -} - -////////// Implementation of HashTable creation functions ////////// - -HashTable* HashTable::create(int keyType) { - return new BasicHashTable(keyType); -} - -HashTable::Iterator* HashTable::Iterator::create(HashTable& hashTable) { - // "hashTable" is assumed to be a BasicHashTable - return new BasicHashTable::Iterator((BasicHashTable&)hashTable); -} - -////////// Implementation of internal member functions ////////// - -BasicHashTable::TableEntry* BasicHashTable -::lookupKey(char const* key, unsigned& index) const { - TableEntry* entry; - index = hashIndexFromKey(key); - - for (entry = fBuckets[index]; entry != NULL; entry = entry->fNext) { - if (keyMatches(key, entry->key)) break; - } - - return entry; -} - -Boolean BasicHashTable -::keyMatches(char const* key1, char const* key2) const { - // The way we check the keys for a match depends upon their type: - if (fKeyType == STRING_HASH_KEYS) { - return (strcmp(key1, key2) == 0); - } else if (fKeyType == ONE_WORD_HASH_KEYS) { - return (key1 == key2); - } else { - unsigned* k1 = (unsigned*)key1; - unsigned* k2 = (unsigned*)key2; - - for (int i = 0; i < fKeyType; ++i) { - if (k1[i] != k2[i]) return False; // keys differ - } - return True; - } -} - -BasicHashTable::TableEntry* BasicHashTable -::insertNewEntry(unsigned index, char const* key) { - TableEntry* entry = new TableEntry(); - entry->fNext = fBuckets[index]; - fBuckets[index] = entry; - - ++fNumEntries; - assignKey(entry, key); - - return entry; -} - -void BasicHashTable::assignKey(TableEntry* entry, char const* key) { - // The way we assign the key depends upon its type: - if (fKeyType == STRING_HASH_KEYS) { - entry->key = strDup(key); - } else if (fKeyType == ONE_WORD_HASH_KEYS) { - entry->key = key; - } else if (fKeyType > 0) { - unsigned* keyFrom = (unsigned*)key; - unsigned* keyTo = new unsigned[fKeyType]; - for (int i = 0; i < fKeyType; ++i) keyTo[i] = keyFrom[i]; - - entry->key = (char const*)keyTo; - } -} - -void BasicHashTable::deleteEntry(unsigned index, TableEntry* entry) { - TableEntry** ep = &fBuckets[index]; - - Boolean foundIt = False; - while (*ep != NULL) { - if (*ep == entry) { - foundIt = True; - *ep = entry->fNext; - break; - } - ep = &((*ep)->fNext); - } - - if (!foundIt) { // shouldn't happen -#ifdef DEBUG - fprintf(stderr, "BasicHashTable[%p]::deleteEntry(%d,%p): internal error - not found (first entry %p", this, index, entry, fBuckets[index]); - if (fBuckets[index] != NULL) fprintf(stderr, ", next entry %p", fBuckets[index]->fNext); - fprintf(stderr, ")\n"); -#endif - } - - --fNumEntries; - deleteKey(entry); - delete entry; -} - -void BasicHashTable::deleteKey(TableEntry* entry) { - // The way we delete the key depends upon its type: - if (fKeyType == ONE_WORD_HASH_KEYS) { - entry->key = NULL; - } else { - delete[] (char*)entry->key; - entry->key = NULL; - } -} - -void BasicHashTable::rebuild() { - // Remember the existing table size: - unsigned oldSize = fNumBuckets; - TableEntry** oldBuckets = fBuckets; - - // Create the new sized table: - fNumBuckets *= 4; - fBuckets = new TableEntry*[fNumBuckets]; - for (unsigned i = 0; i < fNumBuckets; ++i) { - fBuckets[i] = NULL; - } - fRebuildSize *= 4; - fDownShift -= 2; - fMask = (fMask<<2)|0x3; - - // Rehash the existing entries into the new table: - for (TableEntry** oldChainPtr = oldBuckets; oldSize > 0; - --oldSize, ++oldChainPtr) { - for (TableEntry* hPtr = *oldChainPtr; hPtr != NULL; - hPtr = *oldChainPtr) { - *oldChainPtr = hPtr->fNext; - - unsigned index = hashIndexFromKey(hPtr->key); - - hPtr->fNext = fBuckets[index]; - fBuckets[index] = hPtr; - } - } - - // Free the old bucket array, if it was dynamically allocated: - if (oldBuckets != fStaticBuckets) delete[] oldBuckets; -} - -unsigned BasicHashTable::hashIndexFromKey(char const* key) const { - unsigned result = 0; - - if (fKeyType == STRING_HASH_KEYS) { - while (1) { - char c = *key++; - if (c == 0) break; - result += (result<<3) + (unsigned)c; - } - result &= fMask; - } else if (fKeyType == ONE_WORD_HASH_KEYS) { - result = randomIndex((unsigned long)key); - } else { - unsigned* k = (unsigned*)key; - unsigned long sum = 0; - for (int i = 0; i < fKeyType; ++i) { - sum += k[i]; - } - result = randomIndex(sum); - } - - return result; -} - diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicTaskScheduler.cpp b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicTaskScheduler.cpp deleted file mode 100644 index b41bc5664a8..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicTaskScheduler.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Usage Environment: for a simple, non-scripted, console application -// Implementation - - -#ifndef IMN_PIM -#include "BasicUsageEnvironment.hh" -#include "HandlerSet.hh" -#include // for exit() -#include -#if defined(_QNX4) -#include -#include -#endif - -////////// BasicTaskScheduler ////////// - -BasicTaskScheduler* BasicTaskScheduler::createNew() { - return new BasicTaskScheduler(); -} - -BasicTaskScheduler::BasicTaskScheduler() - : fMaxNumSockets(0) { - FD_ZERO(&fReadSet); -} - -BasicTaskScheduler::~BasicTaskScheduler() { -} - -#ifndef MILLION -#define MILLION 1000000 -#endif - -void BasicTaskScheduler::SingleStep(unsigned maxDelayTime) { - fd_set readSet = fReadSet; // make a copy for this select() call - - DelayInterval const& timeToDelay = fDelayQueue.timeToNextAlarm(); - struct timeval tv_timeToDelay; - tv_timeToDelay.tv_sec = timeToDelay.seconds(); - tv_timeToDelay.tv_usec = timeToDelay.useconds(); - // Very large "tv_sec" values cause select() to fail. - // Don't make it any larger than 1 million seconds (11.5 days) - const long MAX_TV_SEC = MILLION; - if (tv_timeToDelay.tv_sec > MAX_TV_SEC) { - tv_timeToDelay.tv_sec = MAX_TV_SEC; - } - // Also check our "maxDelayTime" parameter (if it's > 0): - if (maxDelayTime > 0 && - (tv_timeToDelay.tv_sec > (long)maxDelayTime/MILLION || - (tv_timeToDelay.tv_sec == (long)maxDelayTime/MILLION && - tv_timeToDelay.tv_usec > (long)maxDelayTime%MILLION))) { - tv_timeToDelay.tv_sec = maxDelayTime/MILLION; - tv_timeToDelay.tv_usec = maxDelayTime%MILLION; - } - - int selectResult = select(fMaxNumSockets, &readSet, NULL, NULL, - &tv_timeToDelay); - if (selectResult < 0) { -#if defined(__WIN32__) || defined(_WIN32) - int err = WSAGetLastError(); - // For some unknown reason, select() in Windoze sometimes fails with WSAEINVAL if - // it was called with no entries set in "readSet". If this happens, ignore it: - if (err == WSAEINVAL && readSet.fd_count == 0) { - err = 0; - // To stop this from happening again, create a dummy readable socket: - int dummySocketNum = socket(AF_INET, SOCK_DGRAM, 0); - FD_SET((unsigned)dummySocketNum, &fReadSet); - } - if (err != 0) { -#else - if (errno != EINTR && errno != EAGAIN) { -#endif - // Unexpected error - treat this as fatal: -#if !defined(_WIN32_WCE) - perror("BasicTaskScheduler::SingleStep(): select() fails"); -#endif - exit(0); - } - } - - // Handle any delayed event that may have come due: - fDelayQueue.handleAlarm(); - - // Call the handler function for one readable socket: - HandlerIterator iter(*fReadHandlers); - HandlerDescriptor* handler; - // To ensure forward progress through the handlers, begin past the last - // socket number that we handled: - if (fLastHandledSocketNum >= 0) { - while ((handler = iter.next()) != NULL) { - if (handler->socketNum == fLastHandledSocketNum) break; - } - if (handler == NULL) { - fLastHandledSocketNum = -1; - iter.reset(); // start from the beginning instead - } - } - while ((handler = iter.next()) != NULL) { - if (FD_ISSET(handler->socketNum, &readSet) && - FD_ISSET(handler->socketNum, &fReadSet) /* sanity check */ && - handler->handlerProc != NULL) { - fLastHandledSocketNum = handler->socketNum; - // Note: we set "fLastHandledSocketNum" before calling the handler, - // in case the handler calls "doEventLoop()" reentrantly. - (*handler->handlerProc)(handler->clientData, SOCKET_READABLE); - break; - } - } - if (handler == NULL && fLastHandledSocketNum >= 0) { - // We didn't call a handler, but we didn't get to check all of them, - // so try again from the beginning: - iter.reset(); - while ((handler = iter.next()) != NULL) { - if (FD_ISSET(handler->socketNum, &readSet) && - FD_ISSET(handler->socketNum, &fReadSet) /* sanity check */ && - handler->handlerProc != NULL) { - fLastHandledSocketNum = handler->socketNum; - // Note: we set "fLastHandledSocketNum" before calling the handler, - // in case the handler calls "doEventLoop()" reentrantly. - (*handler->handlerProc)(handler->clientData, SOCKET_READABLE); - break; - } - } - if (handler == NULL) fLastHandledSocketNum = -1;//because we didn't call a handler - } -} - -void BasicTaskScheduler::turnOnBackgroundReadHandling(int socketNum, - BackgroundHandlerProc* handlerProc, - void* clientData) { - if (socketNum < 0) return; - FD_SET((unsigned)socketNum, &fReadSet); - fReadHandlers->assignHandler(socketNum, handlerProc, clientData); - - if (socketNum+1 > fMaxNumSockets) { - fMaxNumSockets = socketNum+1; - } -} - -void BasicTaskScheduler::turnOffBackgroundReadHandling(int socketNum) { - if (socketNum < 0) return; - FD_CLR((unsigned)socketNum, &fReadSet); - fReadHandlers->removeHandler(socketNum); - - if (socketNum+1 == fMaxNumSockets) { - --fMaxNumSockets; - } -} -#endif - diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicTaskScheduler0.cpp b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicTaskScheduler0.cpp deleted file mode 100644 index bc834af14a6..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicTaskScheduler0.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Usage Environment: for a simple, non-scripted, console application -// Implementation - -#include "BasicUsageEnvironment0.hh" -#include "HandlerSet.hh" - -////////// A subclass of DelayQueueEntry, -////////// used to implement BasicTaskScheduler0::scheduleDelayedTask() - -class AlarmHandler: public DelayQueueEntry { -public: - AlarmHandler(TaskFunc* proc, void* clientData, DelayInterval timeToDelay) - : DelayQueueEntry(timeToDelay), fProc(proc), fClientData(clientData) { - } - -private: // redefined virtual functions - virtual void handleTimeout() { - (*fProc)(fClientData); - DelayQueueEntry::handleTimeout(); - } - -private: - TaskFunc* fProc; - void* fClientData; -}; - - -////////// BasicTaskScheduler0 ////////// - -BasicTaskScheduler0::BasicTaskScheduler0() - : fLastHandledSocketNum(-1) { - fReadHandlers = new HandlerSet; -} - -BasicTaskScheduler0::~BasicTaskScheduler0() { - delete fReadHandlers; -} - -TaskToken BasicTaskScheduler0::scheduleDelayedTask(int64_t microseconds, - TaskFunc* proc, - void* clientData) { - if (microseconds < 0) microseconds = 0; - DelayInterval timeToDelay((long)(microseconds/1000000), (long)(microseconds%1000000)); - AlarmHandler* alarmHandler = new AlarmHandler(proc, clientData, timeToDelay); - fDelayQueue.addEntry(alarmHandler); - - return (void*)(alarmHandler->token()); -} - -void BasicTaskScheduler0::unscheduleDelayedTask(TaskToken& prevTask) { - DelayQueueEntry* alarmHandler = fDelayQueue.removeEntry((long)prevTask); - prevTask = NULL; - delete alarmHandler; -} - -void BasicTaskScheduler0::doEventLoop(char* watchVariable) { - // Repeatedly loop, handling readble sockets and timed events: - while (1) { - if (watchVariable != NULL && *watchVariable != 0) break; - SingleStep(); - } -} - - -////////// HandlerSet (etc.) implementation ////////// - -HandlerDescriptor::HandlerDescriptor(HandlerDescriptor* nextHandler) { - // Link this descriptor into a doubly-linked list: - if (nextHandler == this) { // initialization - fNextHandler = fPrevHandler = this; - } else { - fNextHandler = nextHandler; - fPrevHandler = nextHandler->fPrevHandler; - nextHandler->fPrevHandler = this; - fPrevHandler->fNextHandler = this; - } -} - -HandlerDescriptor::~HandlerDescriptor() { - // Unlink this descriptor from a doubly-linked list: - fNextHandler->fPrevHandler = fPrevHandler; - fPrevHandler->fNextHandler = fNextHandler; -} - -HandlerSet::HandlerSet() - : fHandlers(&fHandlers) { - fHandlers.socketNum = -1; // shouldn't ever get looked at, but in case... -} - -HandlerSet::~HandlerSet() { - // Delete each handler descriptor: - while (fHandlers.fNextHandler != &fHandlers) { - delete fHandlers.fNextHandler; // changes fHandlers->fNextHandler - } -} - -void HandlerSet -::assignHandler(int socketNum, - TaskScheduler::BackgroundHandlerProc* handlerProc, - void* clientData) { - // First, see if there's already a handler for this socket: - HandlerDescriptor* handler; - HandlerIterator iter(*this); - while ((handler = iter.next()) != NULL) { - if (handler->socketNum == socketNum) break; - } - if (handler == NULL) { // No existing handler, so create a new descr: - handler = new HandlerDescriptor(fHandlers.fNextHandler); - handler->socketNum = socketNum; - } - - handler->handlerProc = handlerProc; - handler->clientData = clientData; -} - -void HandlerSet::removeHandler(int socketNum) { - HandlerDescriptor* handler; - HandlerIterator iter(*this); - while ((handler = iter.next()) != NULL) { - if (handler->socketNum == socketNum) { - delete handler; - break; - } - } -} - -HandlerIterator::HandlerIterator(HandlerSet& handlerSet) - : fOurSet(handlerSet) { - reset(); -} - -HandlerIterator::~HandlerIterator() { -} - -void HandlerIterator::reset() { - fNextPtr = fOurSet.fHandlers.fNextHandler; -} - -HandlerDescriptor* HandlerIterator::next() { - HandlerDescriptor* result = fNextPtr; - if (result == &fOurSet.fHandlers) { // no more - result = NULL; - } else { - fNextPtr = fNextPtr->fNextHandler; - } - - return result; -} diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicUsageEnvironment.cpp b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicUsageEnvironment.cpp deleted file mode 100644 index 8b74558c054..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicUsageEnvironment.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Usage Environment: for a simple, non-scripted, console application -// Implementation - -#ifndef IMN_PIM -#include "BasicUsageEnvironment.hh" -#include // for exit() -#include - -////////// BasicUsageEnvironment ////////// - -#if defined(__WIN32__) || defined(_WIN32) -extern "C" int initializeWinsockIfNecessary(); -#endif - -BasicUsageEnvironment::BasicUsageEnvironment(TaskScheduler& taskScheduler) -: BasicUsageEnvironment0(taskScheduler) { -#if defined(__WIN32__) || defined(_WIN32) - if (!initializeWinsockIfNecessary()) { - setResultErrMsg("Failed to initialize 'winsock': "); - reportBackgroundError(); - exit(1); - } -#endif -} - -BasicUsageEnvironment::~BasicUsageEnvironment() { -} - -BasicUsageEnvironment* -BasicUsageEnvironment::createNew(TaskScheduler& taskScheduler) { - return new BasicUsageEnvironment(taskScheduler); -} - -int BasicUsageEnvironment::getErrno() const { -#if defined(__WIN32__) || defined(_WIN32) -#ifndef _WIN32_WCE - if (errno == 0) { - errno = WSAGetLastError(); - } -#endif -#endif -#if defined(_WIN32_WCE) - return WSAGetLastError(); -#else - return errno; -#endif -} - -UsageEnvironment& BasicUsageEnvironment::operator<<(char const* str) { - fprintf(stderr, "%s", str); - return *this; -} - -UsageEnvironment& BasicUsageEnvironment::operator<<(int i) { - fprintf(stderr, "%d", i); - return *this; -} - -UsageEnvironment& BasicUsageEnvironment::operator<<(unsigned u) { - fprintf(stderr, "%u", u); - return *this; -} - -UsageEnvironment& BasicUsageEnvironment::operator<<(double d) { - fprintf(stderr, "%f", d); - return *this; -} - -UsageEnvironment& BasicUsageEnvironment::operator<<(void* p) { - fprintf(stderr, "%p", p); - return *this; -} -#endif - diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicUsageEnvironment0.cpp b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicUsageEnvironment0.cpp deleted file mode 100644 index 827dbdaea87..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/BasicUsageEnvironment0.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Usage Environment: for a simple, non-scripted, console application -// Implementation - -#include "BasicUsageEnvironment0.hh" -#include - -////////// BasicUsageEnvironment ////////// - -BasicUsageEnvironment0::BasicUsageEnvironment0(TaskScheduler& taskScheduler) - : UsageEnvironment(taskScheduler), - fBufferMaxSize(RESULT_MSG_BUFFER_MAX) { - reset(); -} - -BasicUsageEnvironment0::~BasicUsageEnvironment0() { -} - -void BasicUsageEnvironment0::reset() { - fCurBufferSize = 0; - fResultMsgBuffer[fCurBufferSize] = '\0'; -} - - -// Implementation of virtual functions: - -char const* BasicUsageEnvironment0::getResultMsg() const { - return fResultMsgBuffer; -} - -void BasicUsageEnvironment0::setResultMsg(MsgString msg) { - reset(); - appendToResultMsg(msg); -} - -void BasicUsageEnvironment0::setResultMsg(MsgString msg1, MsgString msg2) { - setResultMsg(msg1); - appendToResultMsg(msg2); -} - -void BasicUsageEnvironment0::setResultMsg(MsgString msg1, MsgString msg2, - MsgString msg3) { - setResultMsg(msg1, msg2); - appendToResultMsg(msg3); -} - -void BasicUsageEnvironment0::setResultErrMsg(MsgString msg) { - setResultMsg(msg); - -#ifndef _WIN32_WCE - appendToResultMsg(strerror(getErrno())); -#endif -} - -void BasicUsageEnvironment0::appendToResultMsg(MsgString msg) { - char* curPtr = &fResultMsgBuffer[fCurBufferSize]; - unsigned spaceAvailable = fBufferMaxSize - fCurBufferSize; - unsigned msgLength = strlen(msg); - - // Copy only enough of "msg" as will fit: - if (msgLength > spaceAvailable-1) { - msgLength = spaceAvailable-1; - } - - memmove(curPtr, (char*)msg, msgLength); - fCurBufferSize += msgLength; - fResultMsgBuffer[fCurBufferSize] = '\0'; -} - -void BasicUsageEnvironment0::reportBackgroundError() { - fputs(fResultMsgBuffer, stderr); -} - diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/COPYING b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/COPYING deleted file mode 100644 index 3b204400cf3..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/COPYING +++ /dev/null @@ -1,458 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/DelayQueue.cpp b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/DelayQueue.cpp deleted file mode 100644 index d247476e510..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/DelayQueue.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000, Live Networks, Inc. All rights reserved -// Help by Carlo Bonamico to get working for Windows -// Delay queue -// Implementation - -#include "DelayQueue.hh" -#include "GroupsockHelper.hh" - -static const int MILLION = 1000000; - -///// Timeval ///// - -int Timeval::operator>=(const Timeval& arg2) const { - return seconds() > arg2.seconds() - || (seconds() == arg2.seconds() - && useconds() >= arg2.useconds()); -} - -void Timeval::operator+=(const DelayInterval& arg2) { - secs() += arg2.seconds(); usecs() += arg2.useconds(); - if (usecs() >= MILLION) { - usecs() -= MILLION; - ++secs(); - } -} - -void Timeval::operator-=(const DelayInterval& arg2) { - secs() -= arg2.seconds(); usecs() -= arg2.useconds(); - if (usecs() < 0) { - usecs() += MILLION; - --secs(); - } - if (secs() < 0) - secs() = usecs() = 0; -} - -DelayInterval operator-(const Timeval& arg1, const Timeval& arg2) { - time_base_seconds secs = arg1.seconds() - arg2.seconds(); - time_base_seconds usecs = arg1.useconds() - arg2.useconds(); - - if (usecs < 0) { - usecs += MILLION; - --secs; - } - if (secs < 0) - return DELAY_ZERO; - else - return DelayInterval(secs, usecs); -} - - -///// DelayInterval ///// - -DelayInterval operator*(short arg1, const DelayInterval& arg2) { - time_base_seconds result_seconds = arg1*arg2.seconds(); - time_base_seconds result_useconds = arg1*arg2.useconds(); - - time_base_seconds carry = result_useconds/MILLION; - result_useconds -= carry*MILLION; - result_seconds += carry; - - return DelayInterval(result_seconds, result_useconds); -} - -#ifndef INT_MAX -#define INT_MAX 0x7FFFFFFF -#endif -const DelayInterval DELAY_ZERO(0, 0); -const DelayInterval DELAY_SECOND(1, 0); -const DelayInterval ETERNITY(INT_MAX, MILLION-1); -// used internally to make the implementation work - - -///// DelayQueueEntry ///// - -long DelayQueueEntry::tokenCounter = 0; - -DelayQueueEntry::DelayQueueEntry(DelayInterval delay) - : fDeltaTimeRemaining(delay) { - fNext = fPrev = this; - fToken = ++tokenCounter; -} - -DelayQueueEntry::~DelayQueueEntry() { -} - -void DelayQueueEntry::handleTimeout() { - delete this; -} - - -///// DelayQueue ///// - -DelayQueue::DelayQueue() - : DelayQueueEntry(ETERNITY) { - fLastSyncTime = TimeNow(); -} - -DelayQueue::~DelayQueue() { - while (fNext != this) removeEntry(fNext); -} - -void DelayQueue::addEntry(DelayQueueEntry* newEntry) { - synchronize(); - - DelayQueueEntry* cur = head(); - while (newEntry->fDeltaTimeRemaining >= cur->fDeltaTimeRemaining) { - newEntry->fDeltaTimeRemaining -= cur->fDeltaTimeRemaining; - cur = cur->fNext; - } - - cur->fDeltaTimeRemaining -= newEntry->fDeltaTimeRemaining; - - // Add "newEntry" to the queue, just before "cur": - newEntry->fNext = cur; - newEntry->fPrev = cur->fPrev; - cur->fPrev = newEntry->fPrev->fNext = newEntry; -} - -void DelayQueue::updateEntry(DelayQueueEntry* entry, DelayInterval newDelay) { - if (entry == NULL) return; - - removeEntry(entry); - entry->fDeltaTimeRemaining = newDelay; - addEntry(entry); -} - -void DelayQueue::updateEntry(long tokenToFind, DelayInterval newDelay) { - DelayQueueEntry* entry = findEntryByToken(tokenToFind); - updateEntry(entry, newDelay); -} - -void DelayQueue::removeEntry(DelayQueueEntry* entry) { - if (entry == NULL || entry->fNext == NULL) return; - - entry->fNext->fDeltaTimeRemaining += entry->fDeltaTimeRemaining; - entry->fPrev->fNext = entry->fNext; - entry->fNext->fPrev = entry->fPrev; - entry->fNext = entry->fPrev = NULL; - // in case we should try to remove it again -} - -DelayQueueEntry* DelayQueue::removeEntry(long tokenToFind) { - DelayQueueEntry* entry = findEntryByToken(tokenToFind); - removeEntry(entry); - return entry; -} - -DelayInterval const& DelayQueue::timeToNextAlarm() { - if (head()->fDeltaTimeRemaining == DELAY_ZERO) return DELAY_ZERO; // a common case - - synchronize(); - return head()->fDeltaTimeRemaining; -} - -void DelayQueue::handleAlarm() { - if (head()->fDeltaTimeRemaining != DELAY_ZERO) synchronize(); - - if (head()->fDeltaTimeRemaining == DELAY_ZERO) { - // This event is due to be handled: - DelayQueueEntry* toRemove = head(); - removeEntry(toRemove); // do this first, in case handler accesses queue - - toRemove->handleTimeout(); - } -} - -DelayQueueEntry* DelayQueue::findEntryByToken(long tokenToFind) { - DelayQueueEntry* cur = head(); - while (cur != this) { - if (cur->token() == tokenToFind) return cur; - cur = cur->fNext; - } - - return NULL; -} - -void DelayQueue::synchronize() { - // First, figure out how much time has elapsed since the last sync: - EventTime timeNow = TimeNow(); - DelayInterval timeSinceLastSync = timeNow - fLastSyncTime; - fLastSyncTime = timeNow; - - // Then, adjust the delay queue for any entries whose time is up: - DelayQueueEntry* curEntry = head(); - while (timeSinceLastSync >= curEntry->fDeltaTimeRemaining) { - timeSinceLastSync -= curEntry->fDeltaTimeRemaining; - curEntry->fDeltaTimeRemaining = DELAY_ZERO; - curEntry = curEntry->fNext; - } - curEntry->fDeltaTimeRemaining -= timeSinceLastSync; -} - - -///// EventTime ///// - -EventTime TimeNow() { - struct timeval tvNow; - - gettimeofday(&tvNow, NULL); - - return EventTime(tvNow.tv_sec, tvNow.tv_usec); -} - -DelayInterval TimeRemainingUntil(const EventTime& futureEvent) { - return futureEvent - TimeNow(); -} - -const EventTime THE_END_OF_TIME(INT_MAX); diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicHashTable.hh b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicHashTable.hh deleted file mode 100644 index 2d00136a5de..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicHashTable.hh +++ /dev/null @@ -1,101 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Hash Table implementation -// C++ header - -#ifndef _BASIC_HASH_TABLE_HH -#define _BASIC_HASH_TABLE_HH - -#ifndef _HASH_TABLE_HH -#include "HashTable.hh" -#endif - -// A simple hash table implementation, inspired by the hash table -// implementation used in Tcl 7.6: - -#define SMALL_HASH_TABLE_SIZE 4 - -class BasicHashTable: public HashTable { -private: - class TableEntry; // forward - -public: - BasicHashTable(int keyType); - virtual ~BasicHashTable(); - - // Used to iterate through the members of the table: - class Iterator; friend class Iterator; // to make Sun's C++ compiler happy - class Iterator: public HashTable::Iterator { - public: - Iterator(BasicHashTable& table); - - private: // implementation of inherited pure virtual functions - void* next(char const*& key); // returns 0 if none - - private: - BasicHashTable& fTable; - unsigned fNextIndex; // index of next bucket to be enumerated after this - TableEntry* fNextEntry; // next entry in the current bucket - }; - -private: // implementation of inherited pure virtual functions - virtual void* Add(char const* key, void* value); - // Returns the old value if different, otherwise 0 - virtual Boolean Remove(char const* key); - virtual void* Lookup(char const* key) const; - // Returns 0 if not found - virtual unsigned numEntries() const; - -private: - class TableEntry { - public: - TableEntry* fNext; - char const* key; - void* value; - }; - - TableEntry* lookupKey(char const* key, unsigned& index) const; - // returns entry matching "key", or NULL if none - Boolean keyMatches(char const* key1, char const* key2) const; - // used to implement "lookupKey()" - - TableEntry* insertNewEntry(unsigned index, char const* key); - // creates a new entry, and inserts it in the table - void assignKey(TableEntry* entry, char const* key); - // used to implement "insertNewEntry()" - - void deleteEntry(unsigned index, TableEntry* entry); - void deleteKey(TableEntry* entry); - // used to implement "deleteEntry()" - - void rebuild(); // rebuilds the table as its size increases - - unsigned hashIndexFromKey(char const* key) const; - // used to implement many of the routines above - - unsigned randomIndex(unsigned long i) const { - return (((i*1103515245) >> fDownShift) & fMask); - } - -private: - TableEntry** fBuckets; // pointer to bucket array - TableEntry* fStaticBuckets[SMALL_HASH_TABLE_SIZE];// used for small tables - unsigned fNumBuckets, fNumEntries, fRebuildSize, fDownShift, fMask; - int fKeyType; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment.hh b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment.hh deleted file mode 100644 index 776d842ca2f..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment.hh +++ /dev/null @@ -1,71 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Usage Environment: for a simple, non-scripted, console application -// C++ header - -#ifndef _BASIC_USAGE_ENVIRONMENT_HH -#define _BASIC_USAGE_ENVIRONMENT_HH - -#ifndef _BASIC_USAGE_ENVIRONMENT0_HH -#include "BasicUsageEnvironment0.hh" -#endif - -class BasicUsageEnvironment: public BasicUsageEnvironment0 { -public: - static BasicUsageEnvironment* createNew(TaskScheduler& taskScheduler); - - // redefined virtual functions: - virtual int getErrno() const; - - virtual UsageEnvironment& operator<<(char const* str); - virtual UsageEnvironment& operator<<(int i); - virtual UsageEnvironment& operator<<(unsigned u); - virtual UsageEnvironment& operator<<(double d); - virtual UsageEnvironment& operator<<(void* p); - -protected: - BasicUsageEnvironment(TaskScheduler& taskScheduler); - // called only by "createNew()" (or subclass constructors) - virtual ~BasicUsageEnvironment(); -}; - - -class BasicTaskScheduler: public BasicTaskScheduler0 { -public: - static BasicTaskScheduler* createNew(); - virtual ~BasicTaskScheduler(); - -protected: - BasicTaskScheduler(); - // called only by "createNew()" - -protected: - // Redefined virtual functions: - virtual void SingleStep(unsigned maxDelayTime); - - virtual void turnOnBackgroundReadHandling(int socketNum, - BackgroundHandlerProc* handlerProc, - void* clientData); - virtual void turnOffBackgroundReadHandling(int socketNum); - -protected: - // To implement background reads: - int fMaxNumSockets; - fd_set fReadSet; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment0.hh b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment0.hh deleted file mode 100644 index 434d6e6b864..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment0.hh +++ /dev/null @@ -1,101 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Usage Environment: for a simple, non-scripted, console application -// C++ header - -#ifndef _BASIC_USAGE_ENVIRONMENT0_HH -#define _BASIC_USAGE_ENVIRONMENT0_HH - -#ifndef _BASICUSAGEENVIRONMENT_VERSION_HH -#include "BasicUsageEnvironment_version.hh" -#endif - -#ifndef _USAGE_ENVIRONMENT_HH -#include "UsageEnvironment.hh" -#endif - -#ifndef _DELAY_QUEUE_HH -#include "DelayQueue.hh" -#endif - -#define RESULT_MSG_BUFFER_MAX 1000 - -// An abstract base class, useful for subclassing -// (e.g., to redefine the implementation of "operator<<") -class BasicUsageEnvironment0: public UsageEnvironment { -public: - // redefined virtual functions: - virtual MsgString getResultMsg() const; - - virtual void setResultMsg(MsgString msg); - virtual void setResultMsg(MsgString msg1, - MsgString msg2); - virtual void setResultMsg(MsgString msg1, - MsgString msg2, - MsgString msg3); - virtual void setResultErrMsg(MsgString msg); - - virtual void appendToResultMsg(MsgString msg); - - virtual void reportBackgroundError(); - -protected: - BasicUsageEnvironment0(TaskScheduler& taskScheduler); - virtual ~BasicUsageEnvironment0(); - -private: - void reset(); - - char fResultMsgBuffer[RESULT_MSG_BUFFER_MAX]; - unsigned fCurBufferSize; - unsigned fBufferMaxSize; -}; - -class HandlerSet; // forward - -// An abstract base class, useful for subclassing -// (e.g., to redefine the implementation of socket event handling) -class BasicTaskScheduler0: public TaskScheduler { -public: - virtual ~BasicTaskScheduler0(); - - virtual void SingleStep(unsigned maxDelayTime = 0) = 0; - // "maxDelayTime" is in microseconds. It allows a subclass to impose a limit - // on how long "select()" can delay, in case it wants to also do polling. - // 0 (the default value) means: There's no maximum; just look at the delay queue - -public: - // Redefined virtual functions: - virtual TaskToken scheduleDelayedTask(int64_t microseconds, TaskFunc* proc, - void* clientData); - virtual void unscheduleDelayedTask(TaskToken& prevTask); - - virtual void doEventLoop(char* watchVariable); - -protected: - BasicTaskScheduler0(); - -protected: - // To implement delayed operations: - DelayQueue fDelayQueue; - - // To implement background reads: - HandlerSet* fReadHandlers; - int fLastHandledSocketNum; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh deleted file mode 100644 index 817bb535344..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh +++ /dev/null @@ -1,10 +0,0 @@ -// Version information for the "BasicUsageEnvironment" library -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. - -#ifndef _BASICUSAGEENVIRONMENT_VERSION_HH -#define _BASICUSAGEENVIRONMENT_VERSION_HH - -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_STRING "2006.05.17" -#define BASICUSAGEENVIRONMENT_LIBRARY_VERSION_INT 1147824000 - -#endif diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/DelayQueue.hh b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/DelayQueue.hh deleted file mode 100644 index a149d63bcaf..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/DelayQueue.hh +++ /dev/null @@ -1,185 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ - // Copyright (c) 1996-2000, Live Networks, Inc. All rights reserved -// Delay queue -// C++ header - -#ifndef _DELAY_QUEUE_HH -#define _DELAY_QUEUE_HH - -#ifndef _NET_COMMON_H -#include "NetCommon.h" -#endif - -#ifdef TIME_BASE -typedef TIME_BASE time_base_seconds; -#else -typedef long time_base_seconds; -#endif - -///// A "Timeval" can be either an absolute time, or a time interval ///// - -class Timeval { -public: - time_base_seconds seconds() const { - return fTv.tv_sec; - } - time_base_seconds seconds() { - return fTv.tv_sec; - } - time_base_seconds useconds() const { - return fTv.tv_usec; - } - time_base_seconds useconds() { - return fTv.tv_usec; - } - - int operator>=(Timeval const& arg2) const; - int operator<=(Timeval const& arg2) const { - return arg2 >= *this; - } - int operator<(Timeval const& arg2) const { - return !(*this >= arg2); - } - int operator>(Timeval const& arg2) const { - return arg2 < *this; - } - int operator==(Timeval const& arg2) const { - return *this >= arg2 && arg2 >= *this; - } - int operator!=(Timeval const& arg2) const { - return !(*this == arg2); - } - - void operator+=(class DelayInterval const& arg2); - void operator-=(class DelayInterval const& arg2); - // returns ZERO iff arg2 >= arg1 - -protected: - Timeval(time_base_seconds seconds, time_base_seconds useconds) { - fTv.tv_sec = seconds; fTv.tv_usec = useconds; - } - -private: - time_base_seconds& secs() { - return (time_base_seconds&)fTv.tv_sec; - } - time_base_seconds& usecs() { - return (time_base_seconds&)fTv.tv_usec; - } - - struct timeval fTv; -}; - -#ifndef max -inline Timeval max(Timeval const& arg1, Timeval const& arg2) { - return arg1 >= arg2 ? arg1 : arg2; -} -#endif -#ifndef min -inline Timeval min(Timeval const& arg1, Timeval const& arg2) { - return arg1 <= arg2 ? arg1 : arg2; -} -#endif - -class DelayInterval operator-(Timeval const& arg1, Timeval const& arg2); -// returns ZERO iff arg2 >= arg1 - - -///// DelayInterval ///// - -class DelayInterval: public Timeval { -public: - DelayInterval(time_base_seconds seconds, time_base_seconds useconds) - : Timeval(seconds, useconds) {} -}; - -DelayInterval operator*(short arg1, DelayInterval const& arg2); - -extern DelayInterval const DELAY_ZERO; -extern DelayInterval const DELAY_SECOND; -DelayInterval const DELAY_MINUTE = 60*DELAY_SECOND; -DelayInterval const DELAY_HOUR = 60*DELAY_MINUTE; -DelayInterval const DELAY_DAY = 24*DELAY_HOUR; - -///// EventTime ///// - -class EventTime: public Timeval { -public: - EventTime(unsigned secondsSinceEpoch = 0, - unsigned usecondsSinceEpoch = 0) - // We use the Unix standard epoch: January 1, 1970 - : Timeval(secondsSinceEpoch, usecondsSinceEpoch) {} -}; - -EventTime TimeNow(); - -DelayInterval TimeRemainingUntil(EventTime const& futureEvent); -// Returns DELAY_ZERO if "futureEvent" has already occurred. - -extern EventTime const THE_END_OF_TIME; - - -///// DelayQueueEntry ///// - -class DelayQueueEntry { -public: - virtual ~DelayQueueEntry(); - - long token() { - return fToken; - } - -protected: // abstract base class - DelayQueueEntry(DelayInterval delay); - - virtual void handleTimeout(); - -private: - friend class DelayQueue; - DelayQueueEntry* fNext; - DelayQueueEntry* fPrev; - DelayInterval fDeltaTimeRemaining; - - long fToken; - static long tokenCounter; -}; - -///// DelayQueue ///// - -class DelayQueue: public DelayQueueEntry { -public: - DelayQueue(); - virtual ~DelayQueue(); - - void addEntry(DelayQueueEntry* newEntry); // returns a token for the entry - void updateEntry(DelayQueueEntry* entry, DelayInterval newDelay); - void updateEntry(long tokenToFind, DelayInterval newDelay); - void removeEntry(DelayQueueEntry* entry); // but doesn't delete it - DelayQueueEntry* removeEntry(long tokenToFind); // but doesn't delete it - - DelayInterval const& timeToNextAlarm(); - void handleAlarm(); - -private: - DelayQueueEntry* head() { return fNext; } - DelayQueueEntry* findEntryByToken(long token); - void synchronize(); // bring the 'time remaining' fields up-to-date - - EventTime fLastSyncTime; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/HandlerSet.hh b/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/HandlerSet.hh deleted file mode 100644 index a112605f9e3..00000000000 --- a/mythtv/libs/libmythlivemedia/BasicUsageEnvironment/include/HandlerSet.hh +++ /dev/null @@ -1,70 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Basic Usage Environment: for a simple, non-scripted, console application -// C++ header - -#ifndef _HANDLER_SET_HH -#define _HANDLER_SET_HH - -////////// HandlerSet (etc.) definition ////////// - -class HandlerDescriptor { - HandlerDescriptor(HandlerDescriptor* nextHandler); - virtual ~HandlerDescriptor(); - -public: - int socketNum; - TaskScheduler::BackgroundHandlerProc* handlerProc; - void* clientData; - -private: - // Descriptors are linked together in a doubly-linked list: - friend class HandlerSet; - friend class HandlerIterator; - HandlerDescriptor* fNextHandler; - HandlerDescriptor* fPrevHandler; -}; - -class HandlerSet { -public: - HandlerSet(); - virtual ~HandlerSet(); - - void assignHandler(int socketNum, - TaskScheduler::BackgroundHandlerProc* handlerProc, - void* clientData); - void removeHandler(int socketNum); - -private: - friend class HandlerIterator; - HandlerDescriptor fHandlers; -}; - -class HandlerIterator { -public: - HandlerIterator(HandlerSet& handlerSet); - virtual ~HandlerIterator(); - - HandlerDescriptor* next(); // returns NULL if none - void reset(); - -private: - HandlerSet& fOurSet; - HandlerDescriptor* fNextPtr; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/COPYING b/mythtv/libs/libmythlivemedia/COPYING deleted file mode 100644 index 3b204400cf3..00000000000 --- a/mythtv/libs/libmythlivemedia/COPYING +++ /dev/null @@ -1,458 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS diff --git a/mythtv/libs/libmythlivemedia/README b/mythtv/libs/libmythlivemedia/README deleted file mode 100644 index 5138604d96a..00000000000 --- a/mythtv/libs/libmythlivemedia/README +++ /dev/null @@ -1,6 +0,0 @@ -For original library see http://www.live555.com/liveMedia/ - -This library has been modified for use by MythTV. - -The Live library is licensed to you under LGPL license located -in the COPYING file in the same directory as this README. diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/COPYING b/mythtv/libs/libmythlivemedia/UsageEnvironment/COPYING deleted file mode 100644 index 3b204400cf3..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/COPYING +++ /dev/null @@ -1,458 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/HashTable.cpp b/mythtv/libs/libmythlivemedia/UsageEnvironment/HashTable.cpp deleted file mode 100644 index c4cd8f25e77..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/HashTable.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2003 Live Networks, Inc. All rights reserved. -// Generic Hash Table -// Implementation - -#include "HashTable.hh" - -HashTable::HashTable() { -} - -HashTable::~HashTable() { -} - -HashTable::Iterator::Iterator() { -} - -HashTable::Iterator::~Iterator() {} - -void* HashTable::RemoveNext() { - Iterator* iter = Iterator::create(*this); - char const* key; - void* removedValue = iter->next(key); - if (removedValue != 0) Remove(key); - - delete iter; - return removedValue; -} diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/UsageEnvironment.cpp b/mythtv/libs/libmythlivemedia/UsageEnvironment/UsageEnvironment.cpp deleted file mode 100644 index 37732841842..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/UsageEnvironment.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2000 Live Networks, Inc. All rights reserved. -// Usage Environment -// Implementation - -#include "UsageEnvironment.hh" - -void UsageEnvironment::reclaim() { - // We delete ourselves only if we have no remainining state: - if (liveMediaPriv == NULL && groupsockPriv == NULL) delete this; -} - -UsageEnvironment::UsageEnvironment(TaskScheduler& scheduler) - : liveMediaPriv(NULL), groupsockPriv(NULL), fScheduler(scheduler) { -} - -UsageEnvironment::~UsageEnvironment() { -} - -TaskScheduler::TaskScheduler() { -} - -TaskScheduler::~TaskScheduler() { -} - -void TaskScheduler::rescheduleDelayedTask(TaskToken& task, - int64_t microseconds, TaskFunc* proc, - void* clientData) { - unscheduleDelayedTask(task); - task = scheduleDelayedTask(microseconds, proc, clientData); -} diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/Boolean.hh b/mythtv/libs/libmythlivemedia/UsageEnvironment/include/Boolean.hh deleted file mode 100644 index 9d2f5f09465..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/Boolean.hh +++ /dev/null @@ -1,34 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -#ifndef _BOOLEAN_HH -#define _BOOLEAN_HH - -#ifdef __BORLANDC__ -#define Boolean bool -#define False false -#define True true -#else -typedef unsigned Boolean; -#ifndef False -const Boolean False = 0; -#endif -#ifndef True -const Boolean True = 1; -#endif - -#endif - -#endif diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/HashTable.hh b/mythtv/libs/libmythlivemedia/UsageEnvironment/include/HashTable.hh deleted file mode 100644 index 97badb51673..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/HashTable.hh +++ /dev/null @@ -1,72 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2003 Live Networks, Inc. All rights reserved. -// Generic Hash Table -// C++ header - -#ifndef _HASH_TABLE_HH -#define _HASH_TABLE_HH - -#ifndef _BOOLEAN_HH -#include "Boolean.hh" -#endif - -class HashTable { - public: - virtual ~HashTable(); - - // The following must be implemented by a particular - // implementation (subclass): - static HashTable* create(int keyType); - - virtual void* Add(char const* key, void* value) = 0; - // Returns the old value if different, otherwise 0 - virtual Boolean Remove(char const* key) = 0; - virtual void* Lookup(char const* key) const = 0; - // Returns 0 if not found - virtual unsigned numEntries() const = 0; - Boolean IsEmpty() const { return numEntries() == 0; } - - // Used to iterate through the members of the table: - class Iterator { - public: - // The following must be implemented by a particular - // implementation (subclass): - static Iterator* create(HashTable& hashTable); - - virtual ~Iterator(); - - virtual void* next(char const*& key) = 0; // returns 0 if none - - protected: - Iterator(); // abstract base class - }; - - // A shortcut that can be used to successively remove each of - // the entries in the table (e.g., so that their values can be - // deleted, if they happen to be pointers to allocated memory). - void* RemoveNext(); - - protected: - HashTable(); // abstract base class -}; - -// Warning: The following are deliberately the same as in -// Tcl's hash table implementation -int const STRING_HASH_KEYS = 0; -int const ONE_WORD_HASH_KEYS = 1; - -#endif diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/UsageEnvironment.hh b/mythtv/libs/libmythlivemedia/UsageEnvironment/include/UsageEnvironment.hh deleted file mode 100644 index ca4e7252c45..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/UsageEnvironment.hh +++ /dev/null @@ -1,143 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2001 Live Networks, Inc. All rights reserved. -// Usage Environment -// C++ header - -#ifndef _USAGE_ENVIRONMENT_HH -#define _USAGE_ENVIRONMENT_HH - -#ifndef _USAGEENVIRONMENT_VERSION_HH -#include "UsageEnvironment_version.hh" -#endif - -#ifndef _NETCOMMON_H -#include "NetCommon.h" -#endif - -#ifndef _STRDUP_HH -// "strDup()" is used often, so include this here, so everyone gets it: -#include "strDup.hh" -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#ifdef __BORLANDC__ -#define _setmode setmode -#define _O_BINARY O_BINARY -#endif - -class TaskScheduler; // forward - -// An abstract base class, subclassed for each use of the library - -class UsageEnvironment { -public: - void reclaim(); - - // task scheduler: - TaskScheduler& taskScheduler() const {return fScheduler;} - - // result message handling: - typedef char const* MsgString; - virtual MsgString getResultMsg() const = 0; - - virtual void setResultMsg(MsgString msg) = 0; - virtual void setResultMsg(MsgString msg1, MsgString msg2) = 0; - virtual void setResultMsg(MsgString msg1, MsgString msg2, MsgString msg3) = 0; - virtual void setResultErrMsg(MsgString msg) = 0; - // like setResultMsg(), except that an 'errno' message is appended - - virtual void appendToResultMsg(MsgString msg) = 0; - - virtual void reportBackgroundError() = 0; - // used to report a (previously set) error message within - // a background event - - // 'errno' - virtual int getErrno() const = 0; - - // 'console' output: - virtual UsageEnvironment& operator<<(char const* str) = 0; - virtual UsageEnvironment& operator<<(int i) = 0; - virtual UsageEnvironment& operator<<(unsigned u) = 0; - virtual UsageEnvironment& operator<<(double d) = 0; - virtual UsageEnvironment& operator<<(void* p) = 0; - - // a pointer to additional, optional, client-specific state - void* liveMediaPriv; - void* groupsockPriv; - -protected: - UsageEnvironment(TaskScheduler& scheduler); // abstract base class - virtual ~UsageEnvironment(); // we are deleted only by reclaim() - -private: - TaskScheduler& fScheduler; -}; - - -typedef void TaskFunc(void* clientData); -typedef void* TaskToken; - -class TaskScheduler { -public: - virtual ~TaskScheduler(); - - virtual TaskToken scheduleDelayedTask(int64_t microseconds, TaskFunc* proc, - void* clientData) = 0; - // Schedules a task to occur (after a delay) when we next - // reach a scheduling point. - // (Does not delay if "microseconds" <= 0) - // Returns a token that can be used in a subsequent call to - // unscheduleDelayedTask() - - virtual void unscheduleDelayedTask(TaskToken& prevTask) = 0; - // (Has no effect if "prevTask" == NULL) - // Sets "prevTask" to NULL afterwards. - - virtual void rescheduleDelayedTask(TaskToken& task, - int64_t microseconds, TaskFunc* proc, - void* clientData); - // Combines "unscheduleDelayedTask()" with "scheduleDelayedTask()" - // (setting "task" to the new task token). - - // For handling socket reads in the background: - typedef void BackgroundHandlerProc(void* clientData, int mask); - // Possible bits to set in "mask". (These are deliberately defined - // the same as those in Tcl, to make a Tcl-based subclass easy.) - #define SOCKET_READABLE (1<<1) - #define SOCKET_WRITABLE (1<<2) - #define SOCKET_EXCEPTION (1<<3) - virtual void turnOnBackgroundReadHandling(int socketNum, - BackgroundHandlerProc* handlerProc, - void* clientData) = 0; - virtual void turnOffBackgroundReadHandling(int socketNum) = 0; - - virtual void doEventLoop(char* watchVariable = NULL) = 0; - // Stops the current thread of control from proceeding, - // but allows delayed tasks (and/or background I/O handling) - // to proceed. - // (If "watchVariable" is not NULL, then we return from this - // routine when *watchVariable != 0) - -protected: - TaskScheduler(); // abstract base class -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/UsageEnvironment_version.hh b/mythtv/libs/libmythlivemedia/UsageEnvironment/include/UsageEnvironment_version.hh deleted file mode 100644 index d5085750905..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/UsageEnvironment_version.hh +++ /dev/null @@ -1,10 +0,0 @@ -// Version information for the "UsageEnvironment" library -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. - -#ifndef _USAGEENVIRONMENT_VERSION_HH -#define _USAGEENVIRONMENT_VERSION_HH - -#define USAGEENVIRONMENT_LIBRARY_VERSION_STRING "2006.05.17" -#define USAGEENVIRONMENT_LIBRARY_VERSION_INT 1147824000 - -#endif diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/strDup.hh b/mythtv/libs/libmythlivemedia/UsageEnvironment/include/strDup.hh deleted file mode 100644 index 9b87270821e..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/include/strDup.hh +++ /dev/null @@ -1,32 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ - -#ifndef _STRDUP_HH -#define _STRDUP_HH - -// Copyright (c) 1996-2003 Live Networks, Inc. All rights reserved. -// A C++ equivalent to the standard C routine "strdup()". -// This generates a char* that can be deleted using "delete[]" -// Header - -char* strDup(char const* str); -// Note: strDup(NULL) returns NULL - -char* strDupSize(char const* str); -// Like "strDup()", except that it *doesn't* copy the original. -// (Instead, it just allocates a string of the same size as the original.) - -#endif diff --git a/mythtv/libs/libmythlivemedia/UsageEnvironment/strDup.cpp b/mythtv/libs/libmythlivemedia/UsageEnvironment/strDup.cpp deleted file mode 100644 index e7b5c4b5da1..00000000000 --- a/mythtv/libs/libmythlivemedia/UsageEnvironment/strDup.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2003 Live Networks, Inc. All rights reserved. -// A C++ equivalent to the standard C routine "strdup()". -// This generates a char* that can be deleted using "delete[]" -// Implementation - -#include "strDup.hh" -#include "string.h" - -char* strDup(char const* str) { - if (str == NULL) return NULL; - size_t len = strlen(str) + 1; - char* copy = new char[len]; - - if (copy != NULL) { - memcpy(copy, str, len); - } - return copy; -} - -char* strDupSize(char const* str) { - if (str == NULL) return NULL; - size_t len = strlen(str) + 1; - char* copy = new char[len]; - - return copy; -} - diff --git a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice.mak b/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice.mak deleted file mode 100644 index 50230e5846b..00000000000 --- a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice.mak +++ /dev/null @@ -1,108 +0,0 @@ -INCLUDES = -I../UsageEnvironment/include -I../groupsock/include -I../liveMedia/include -##### Change the following for your environment: -# Comment out the following line to produce Makefiles that generate debuggable code: -NODEBUG=1 - -# The following definition ensures that we are properly matching -# the WinSock2 library file with the correct header files. -# (will link with "ws2_32.lib" and include "winsock2.h" & "Ws2tcpip.h") -TARGETOS = WINNT - -# If for some reason you wish to use WinSock1 instead, uncomment the -# following two definitions. -# (will link with "wsock32.lib" and include "winsock.h") -#TARGETOS = WIN95 -#APPVER = 4.0 - -!include - -UI_OPTS = $(guilflags) $(guilibsdll) -# Use the following to get a console (e.g., for debugging): -CONSOLE_UI_OPTS = $(conlflags) $(conlibsdll) -CPU=i386 - -TOOLS32 = c:\Program Files\DevStudio\Vc -COMPILE_OPTS = $(INCLUDES) $(cdebug) $(cflags) $(cvarsdll) -I. -I"$(TOOLS32)\include" -C = c -C_COMPILER = "$(TOOLS32)\bin\cl" -C_FLAGS = $(COMPILE_OPTS) -CPP = cpp -CPLUSPLUS_COMPILER = $(C_COMPILER) -CPLUSPLUS_FLAGS = $(COMPILE_OPTS) -OBJ = obj -LINK = $(link) -out: -LIBRARY_LINK = lib -out: -LINK_OPTS_0 = $(linkdebug) msvcirt.lib -LIBRARY_LINK_OPTS = -LINK_OPTS = $(LINK_OPTS_0) $(UI_OPTS) -CONSOLE_LINK_OPTS = $(LINK_OPTS_0) $(CONSOLE_UI_OPTS) -SERVICE_LINK_OPTS = kernel32.lib advapi32.lib shell32.lib -subsystem:console,$(APPVER) -LIB_SUFFIX = lib -LIBS_FOR_CONSOLE_APPLICATION = -LIBS_FOR_GUI_APPLICATION = -MULTIMEDIA_LIBS = winmm.lib -EXE = .exe - -rc32 = "$(TOOLS32)\bin\rc" -.rc.res: - $(rc32) $< -##### End of variables to change - -WINDOWSAUDIOINPUTDEVICE_NOMIXER_LIB = libWindowsAudioInputDevice_noMixer.$(LIB_SUFFIX) -WINDOWSAUDIOINPUTDEVICE_MIXER_LIB = libWindowsAudioInputDevice_mixer.$(LIB_SUFFIX) -ALL = $(WINDOWSAUDIOINPUTDEVICE_NOMIXER_LIB) $(WINDOWSAUDIOINPUTDEVICE_MIXER_LIB) \ - showAudioInputPorts_noMixer$(EXE) showAudioInputPorts_mixer$(EXE) -all:: $(ALL) - -.$(C).$(OBJ): - $(C_COMPILER) -c $(C_FLAGS) $< - -.$(CPP).$(OBJ): - $(CPLUSPLUS_COMPILER) -c $(CPLUSPLUS_FLAGS) $< - -WINDOWSAUDIOINPUTDEVICE_NOMIXER_LIB_OBJS = WindowsAudioInputDevice_common.$(OBJ) WindowsAudioInputDevice_noMixer.$(OBJ) -WINDOWSAUDIOINPUTDEVICE_MIXER_LIB_OBJS = WindowsAudioInputDevice_common.$(OBJ) WindowsAudioInputDevice_mixer.$(OBJ) - -WindowsAudioInputDevice_common.$(CPP): WindowsAudioInputDevice_common.hh -WindowsAudioInputDevice_noMixer.$(CPP): WindowsAudioInputDevice_noMixer.hh -WindowsAudioInputDevice_noMixer.hh: WindowsAudioInputDevice_common.hh -WindowsAudioInputDevice_mixer.$(CPP): WindowsAudioInputDevice_mixer.hh -WindowsAudioInputDevice_mixer.hh: WindowsAudioInputDevice_common.hh - -$(WINDOWSAUDIOINPUTDEVICE_NOMIXER_LIB): $(WINDOWSAUDIOINPUTDEVICE_NOMIXER_LIB_OBJS) \ - $(PLATFORM_SPECIFIC_LIB_OBJS) - $(LIBRARY_LINK)$@ $(LIBRARY_LINK_OPTS) \ - $(WINDOWSAUDIOINPUTDEVICE_NOMIXER_LIB_OBJS) -$(WINDOWSAUDIOINPUTDEVICE_MIXER_LIB): $(WINDOWSAUDIOINPUTDEVICE_MIXER_LIB_OBJS) \ - $(PLATFORM_SPECIFIC_LIB_OBJS) - $(LIBRARY_LINK)$@ $(LIBRARY_LINK_OPTS) \ - $(WINDOWSAUDIOINPUTDEVICE_MIXER_LIB_OBJS) - -USAGE_ENVIRONMENT_DIR = ../UsageEnvironment -USAGE_ENVIRONMENT_LIB = $(USAGE_ENVIRONMENT_DIR)/libUsageEnvironment.$(LIB_SUFFIX) -BASIC_USAGE_ENVIRONMENT_DIR = ../BasicUsageEnvironment -BASIC_USAGE_ENVIRONMENT_LIB = $(BASIC_USAGE_ENVIRONMENT_DIR)/libBasicUsageEnvironment.$(LIB_SUFFIX) -LIVEMEDIA_DIR = ../liveMedia -LIVEMEDIA_LIB = $(LIVEMEDIA_DIR)/libliveMedia.$(LIB_SUFFIX) -GROUPSOCK_DIR = ../groupsock -GROUPSOCK_LIB = $(GROUPSOCK_DIR)/libgroupsock.$(LIB_SUFFIX) -LOCAL_LIBS = $(LIVEMEDIA_LIB) $(GROUPSOCK_LIB) \ - $(USAGE_ENVIRONMENT_LIB) $(BASIC_USAGE_ENVIRONMENT_LIB) -LOCAL_LIBS_NOMIXER = $(WINDOWSAUDIOINPUTDEVICE_NOMIXER_LIB) $(LOCAL_LIBS) -LOCAL_LIBS_MIXER = $(WINDOWSAUDIOINPUTDEVICE_MIXER_LIB) $(LOCAL_LIBS) -MULTIMEDIA_LIBS = winmm.lib -LIBS_NOMIXER = $(LOCAL_LIBS_NOMIXER) $(LIBS_FOR_CONSOLE_APPLICATION) $(MULTIMEDIA_LIBS) -LIBS_MIXER = $(LOCAL_LIBS_MIXER) $(LIBS_FOR_CONSOLE_APPLICATION) $(MULTIMEDIA_LIBS) - -SHOW_AUDIO_INPUT_PORTS_OBJS = showAudioInputPorts.$(OBJ) - -showAudioInputPorts_noMixer$(EXE): $(SHOW_AUDIO_INPUT_PORTS_OBJS) $(LOCAL_LIBS_NOMIXER) - $(LINK)$@ $(CONSOLE_LINK_OPTS) $(SHOW_AUDIO_INPUT_PORTS_OBJS) $(LIBS_NOMIXER) -showAudioInputPorts_mixer$(EXE): $(SHOW_AUDIO_INPUT_PORTS_OBJS) $(LOCAL_LIBS_MIXER) - $(LINK)$@ $(CONSOLE_LINK_OPTS) $(SHOW_AUDIO_INPUT_PORTS_OBJS) $(LIBS_MIXER) - -clean: - -rm -rf *.$(OBJ) $(ALL) tcl2array$(EXE) core *.core *~ - -rm -rf $(TCL_EMBEDDED_CPLUSPLUS_FILES) $(TK_EMBEDDED_CPLUSPLUS_FILES) $(MISC_EMBEDDED_CPLUSPLUS_FILES) - -##### Any additional, platform-specific rules come here: diff --git a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_common.cpp b/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_common.cpp deleted file mode 100644 index 5c9e9cb8daf..00000000000 --- a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_common.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 2001-2004 Live Networks, Inc. All rights reserved. -// Windows implementation of a generic audio input device -// Base class for both library versions: -// One that uses Windows' built-in software mixer; another that doesn't. -// Implementation - -#include "WindowsAudioInputDevice_common.hh" -#include - -////////// WindowsAudioInputDevice_common implementation ////////// - -unsigned WindowsAudioInputDevice_common::_bitsPerSample = 16; - -WindowsAudioInputDevice_common -::WindowsAudioInputDevice_common(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, - unsigned char numChannels, - unsigned samplingFrequency, - unsigned granularityInMS) - : AudioInputDevice(env, bitsPerSample, numChannels, samplingFrequency, granularityInMS), - fCurPortIndex(-1), fHaveStarted(False) { - _bitsPerSample = bitsPerSample; -} - -WindowsAudioInputDevice_common::~WindowsAudioInputDevice_common() { -} - -Boolean WindowsAudioInputDevice_common::initialSetInputPort(int portIndex) { - if (!setInputPort(portIndex)) { - char errMsgPrefix[100]; - sprintf(errMsgPrefix, "Failed to set audio input port number to %d: ", portIndex); - char* errMsgSuffix = strDup(envir().getResultMsg()); - envir().setResultMsg(errMsgPrefix, errMsgSuffix); - delete[] errMsgSuffix; - return False; - } else { - return True; - } -} - -void WindowsAudioInputDevice_common::doGetNextFrame() { - if (!fHaveStarted) { - // Before reading the first audio data, flush any existing data: - while (readHead != NULL) releaseHeadBuffer(); - fHaveStarted = True; - } - fTotalPollingDelay = 0; - audioReadyPoller1(); -} - -void WindowsAudioInputDevice_common::doStopGettingFrames() { - // Turn off the audio poller: - envir().taskScheduler().unscheduleDelayedTask(nextTask()); nextTask() = NULL; -} - -double WindowsAudioInputDevice_common::getAverageLevel() const { - // If the input audio queue is empty, return the previous level, - // otherwise use the input queue to recompute "averageLevel": - if (readHead != NULL) { - double levelTotal = 0.0; - unsigned totNumSamples = 0; - WAVEHDR* curHdr = readHead; - while (1) { - short* samplePtr = (short*)(curHdr->lpData); - unsigned numSamples = blockSize/2; - totNumSamples += numSamples; - - while (numSamples-- > 0) { - short sample = *samplePtr++; - if (sample < 0) sample = -sample; - levelTotal += (unsigned short)sample; - } - - if (curHdr == readTail) break; - curHdr = curHdr->lpNext; - } - averageLevel = levelTotal/(totNumSamples*(double)0x8000); - } - return averageLevel; -} - -void WindowsAudioInputDevice_common::audioReadyPoller(void* clientData) { - WindowsAudioInputDevice_common* inputDevice = (WindowsAudioInputDevice_common*)clientData; - inputDevice->audioReadyPoller1(); -} - -void WindowsAudioInputDevice_common::audioReadyPoller1() { - if (readHead != NULL) { - onceAudioIsReady(); - } else { - unsigned const maxPollingDelay = (100 + fGranularityInMS)*1000; - if (fTotalPollingDelay > maxPollingDelay) { - // We've waited too long for the audio device - assume it's down: - handleClosure(this); - return; - } - - // Try again after a short delay: - unsigned const uSecondsToDelay = fGranularityInMS*1000; - fTotalPollingDelay += uSecondsToDelay; - nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToDelay, - (TaskFunc*)audioReadyPoller, this); - } -} - -void WindowsAudioInputDevice_common::onceAudioIsReady() { - fFrameSize = readFromBuffers(fTo, fMaxSize, fPresentationTime); - if (fFrameSize == 0) { - // The source is no longer readable - handleClosure(this); - return; - } - fDurationInMicroseconds = 1000000/fSamplingFrequency; - - // Call our own 'after getting' function. Because we sometimes get here - // after returning from a delay, we can call this directly, without risking - // infinite recursion - afterGetting(this); -} - -static void CALLBACK waveInCallback(HWAVEIN /*hwi*/, UINT uMsg, - DWORD /*dwInstance*/, DWORD dwParam1, DWORD /*dwParam2*/) { - switch (uMsg) { - case WIM_DATA: - WAVEHDR* hdr = (WAVEHDR*)dwParam1; - WindowsAudioInputDevice_common::waveInProc(hdr); - break; - } -} - -Boolean WindowsAudioInputDevice_common::openWavInPort(int index, unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS) { - uSecsPerByte = (8*1e6)/(_bitsPerSample*numChannels*samplingFrequency); - - // Configure the port, based on the specified parameters: - WAVEFORMATEX wfx; - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = numChannels; - wfx.nSamplesPerSec = samplingFrequency; - wfx.wBitsPerSample = _bitsPerSample; - wfx.nBlockAlign = (numChannels*_bitsPerSample)/8; - wfx.nAvgBytesPerSec = samplingFrequency*wfx.nBlockAlign; - wfx.cbSize = 0; - - blockSize = (wfx.nAvgBytesPerSec*granularityInMS)/1000; - - // Use a 10-second input buffer, to allow for CPU competition from video, etc., - // and also for some audio cards that buffer as much as 5 seconds of audio. - unsigned const bufferSeconds = 10; - numBlocks = (bufferSeconds*1000)/granularityInMS; - - if (!waveIn_open(index, wfx)) return False; - - // Set this process's priority high. I'm not sure how much this is really needed, - // but the "rat" code does this: - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); - return True; -} - -Boolean WindowsAudioInputDevice_common::waveIn_open(unsigned uid, WAVEFORMATEX& wfx) { - if (shWaveIn != NULL) return True; // already open - - do { - waveIn_reset(); - if (waveInOpen(&shWaveIn, uid, &wfx, - (DWORD)waveInCallback, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) break; - - // Allocate read buffers, and headers: - readData = new unsigned char[numBlocks*blockSize]; - if (readData == NULL) break; - - readHdrs = new WAVEHDR[numBlocks]; - if (readHdrs == NULL) break; - readHead = readTail = NULL; - - readTimes = new struct timeval[numBlocks]; - if (readTimes == NULL) break; - - // Initialize headers: - for (unsigned i = 0; i < numBlocks; ++i) { - readHdrs[i].lpData = (char*)&readData[i*blockSize]; - readHdrs[i].dwBufferLength = blockSize; - readHdrs[i].dwFlags = 0; - if (waveInPrepareHeader(shWaveIn, &readHdrs[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR) break; - if (waveInAddBuffer(shWaveIn, &readHdrs[i], sizeof (WAVEHDR)) != MMSYSERR_NOERROR) break; - } - - if (waveInStart(shWaveIn) != MMSYSERR_NOERROR) break; - - hAudioReady = CreateEvent(NULL, TRUE, FALSE, "waveIn Audio Ready"); - return True; - } while (0); - - waveIn_reset(); - return False; -} - -void WindowsAudioInputDevice_common::waveIn_close() { - if (shWaveIn == NULL) return; // already closed - - waveInStop(shWaveIn); - waveInReset(shWaveIn); - - for (unsigned i = 0; i < numBlocks; ++i) { - if (readHdrs[i].dwFlags & WHDR_PREPARED) { - waveInUnprepareHeader(shWaveIn, &readHdrs[i], sizeof (WAVEHDR)); - } - } - - waveInClose(shWaveIn); - waveIn_reset(); -} - -void WindowsAudioInputDevice_common::waveIn_reset() { - shWaveIn = NULL; - - delete[] readData; readData = NULL; - bytesUsedAtReadHead = 0; - - delete[] readHdrs; readHdrs = NULL; - readHead = readTail = NULL; - - delete[] readTimes; readTimes = NULL; - - hAudioReady = NULL; -} - -unsigned WindowsAudioInputDevice_common::readFromBuffers(unsigned char* to, unsigned numBytesWanted, struct timeval& creationTime) { - // Begin by computing the creation time of (the first bytes of) this returned audio data: - if (readHead != NULL) { - int hdrIndex = readHead - readHdrs; - creationTime = readTimes[hdrIndex]; - - // Adjust this time to allow for any data that's already been read from this buffer: - if (bytesUsedAtReadHead > 0) { - creationTime.tv_usec += (unsigned)(uSecsPerByte*bytesUsedAtReadHead); - creationTime.tv_sec += creationTime.tv_usec/1000000; - creationTime.tv_usec %= 1000000; - } - } - - // Then, read from each available buffer, until we have the data that we want: - unsigned numBytesRead = 0; - while (readHead != NULL && numBytesRead < numBytesWanted) { - unsigned thisRead = min(readHead->dwBytesRecorded - bytesUsedAtReadHead, numBytesWanted - numBytesRead); - memmove(&to[numBytesRead], &readHead->lpData[bytesUsedAtReadHead], thisRead); - numBytesRead += thisRead; - bytesUsedAtReadHead += thisRead; - if (bytesUsedAtReadHead == readHead->dwBytesRecorded) { - // We're finished with the block; give it back to the device: - releaseHeadBuffer(); - } - } - - return numBytesRead; -} - -void WindowsAudioInputDevice_common::releaseHeadBuffer() { - WAVEHDR* toRelease = readHead; - if (readHead == NULL) return; - - readHead = readHead->lpNext; - if (readHead == NULL) readTail = NULL; - - toRelease->lpNext = NULL; - toRelease->dwBytesRecorded = 0; - toRelease->dwFlags &= ~WHDR_DONE; - waveInAddBuffer(shWaveIn, toRelease, sizeof (WAVEHDR)); - bytesUsedAtReadHead = 0; -} - -void WindowsAudioInputDevice_common::waveInProc(WAVEHDR* hdr) { - unsigned hdrIndex = hdr - readHdrs; - - // Record the time that the data arrived: - int dontCare; - gettimeofday(&readTimes[hdrIndex], &dontCare); - - // Add the block to the tail of the queue: - hdr->lpNext = NULL; - if (readTail != NULL) { - readTail->lpNext = hdr; - readTail = hdr; - } else { - readHead = readTail = hdr; - } - SetEvent(hAudioReady); -} - -HWAVEIN WindowsAudioInputDevice_common::shWaveIn = NULL; - -unsigned WindowsAudioInputDevice_common::blockSize = 0; -unsigned WindowsAudioInputDevice_common::numBlocks = 0; - -unsigned char* WindowsAudioInputDevice_common::readData = NULL; -DWORD WindowsAudioInputDevice_common::bytesUsedAtReadHead = 0; -double WindowsAudioInputDevice_common::uSecsPerByte = 0.0; -double WindowsAudioInputDevice_common::averageLevel = 0.0; - -WAVEHDR* WindowsAudioInputDevice_common::readHdrs = NULL; -WAVEHDR* WindowsAudioInputDevice_common::readHead = NULL; -WAVEHDR* WindowsAudioInputDevice_common::readTail = NULL; - -struct timeval* WindowsAudioInputDevice_common::readTimes = NULL; - -HANDLE WindowsAudioInputDevice_common::hAudioReady = NULL; diff --git a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_common.hh b/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_common.hh deleted file mode 100644 index 595873725c0..00000000000 --- a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_common.hh +++ /dev/null @@ -1,82 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Windows implementation of a generic audio input device -// Base class for both library versions: -// One that uses Windows' built-in software mixer; another that doesn't. -// C++ header - -#ifndef _WINDOWS_AUDIO_INPUT_DEVICE_COMMON_HH -#define _WINDOWS_AUDIO_INPUT_DEVICE_COMMON_HH - -#ifndef _AUDIO_INPUT_DEVICE_HH -#include "AudioInputDevice.hh" -#endif - -class WindowsAudioInputDevice_common: public AudioInputDevice { -public: - static Boolean openWavInPort(int index, unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS); - static void waveIn_close(); - static void waveInProc(WAVEHDR* hdr); // Windows audio callback function - -protected: - WindowsAudioInputDevice_common(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, unsigned char numChannels, - unsigned samplingFrequency, unsigned granularityInMS); - // virtual base class - - virtual ~WindowsAudioInputDevice_common(); - - Boolean initialSetInputPort(int portIndex); - -protected: - int fCurPortIndex; - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - virtual void doStopGettingFrames(); - virtual double getAverageLevel() const; - -private: - static void audioReadyPoller(void* clientData); - - void audioReadyPoller1(); - void onceAudioIsReady(); - - // Audio input buffering: - static Boolean waveIn_open(unsigned uid, WAVEFORMATEX& wfx); - static void waveIn_reset(); // used to implement both of the above - static unsigned readFromBuffers(unsigned char* to, unsigned numBytesWanted, struct timeval& creationTime); - static void releaseHeadBuffer(); // from the input header queue - -private: - static unsigned _bitsPerSample; - static HWAVEIN shWaveIn; - static unsigned blockSize, numBlocks; - static unsigned char* readData; // buffer for incoming audio data - static DWORD bytesUsedAtReadHead; // number of bytes that have already been read at head - static double uSecsPerByte; // used to adjust the time for # bytes consumed since arrival - static double averageLevel; - static WAVEHDR *readHdrs, *readHead, *readTail; // input header queue - static struct timeval* readTimes; - static HANDLE hAudioReady; // audio ready event - - Boolean fHaveStarted; - unsigned fTotalPollingDelay; // uSeconds -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_mixer.cpp b/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_mixer.cpp deleted file mode 100644 index f9c77e89eb7..00000000000 --- a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_mixer.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 2001-2004 Live Networks, Inc. All rights reserved. -// Windows implementation of a generic audio input device -// This version uses Windows' built-in software mixer. -// Implementation - -#include - -////////// Mixer and AudioInputPort definition ////////// - -class AudioInputPort { -public: - int tag; - DWORD dwComponentType; - char name[MIXER_LONG_NAME_CHARS]; -}; - -class Mixer { -public: - Mixer(); - virtual ~Mixer(); - - void open(unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS); - void open(); // open with default parameters - void getPortsInfo(); - Boolean enableInputPort(unsigned portIndex, char const*& errReason, MMRESULT& errCode); - void close(); - - unsigned index; - HMIXER hMixer; // valid when open - DWORD dwRecLineID; // valid when open - unsigned numPorts; - AudioInputPort* ports; - char name[MAXPNAMELEN]; -}; - - -////////// AudioInputDevice (remaining) implementation ////////// - -AudioInputDevice* -AudioInputDevice::createNew(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, - unsigned char numChannels, - unsigned samplingFrequency, - unsigned granularityInMS) { - Boolean success; - WindowsAudioInputDevice* newSource - = new WindowsAudioInputDevice(env, inputPortNumber, - bitsPerSample, numChannels, - samplingFrequency, granularityInMS, - success); - if (!success) {delete newSource; newSource = NULL;} - - return newSource; -} - -AudioPortNames* AudioInputDevice::getPortNames() { - WindowsAudioInputDevice::initializeIfNecessary(); - - AudioPortNames* portNames = new AudioPortNames; - portNames->numPorts = WindowsAudioInputDevice::numInputPortsTotal; - portNames->portName = new char*[WindowsAudioInputDevice::numInputPortsTotal]; - - // If there's more than one mixer, print only the port name. - // If there's two or more mixers, also include the mixer name - // (to disambiguate port names that may be the same name in different mixers) - char portNameBuffer[2*MAXPNAMELEN+10/*slop*/]; - char mixerNameBuffer[MAXPNAMELEN]; - char const* portNameFmt; - if (WindowsAudioInputDevice::numMixers <= 1) { - portNameFmt = "%s"; - } else { - portNameFmt = "%s (%s)"; - } - - unsigned curPortNum = 0; - for (unsigned i = 0; i < WindowsAudioInputDevice::numMixers; ++i) { - Mixer& mixer = WindowsAudioInputDevice::ourMixers[i]; - - if (WindowsAudioInputDevice::numMixers <= 1) { - mixerNameBuffer[0] = '\0'; - } else { - strncpy(mixerNameBuffer, mixer.name, sizeof mixerNameBuffer); -#if 0 - // Hack: Simplify the mixer name, by truncating after the first space character: - for (int k = 0; k < sizeof mixerNameBuffer && mixerNameBuffer[k] != '\0'; ++k) { - if (mixerNameBuffer[k] == ' ') { - mixerNameBuffer[k] = '\0'; - break; - } - } -#endif - } - - for (unsigned j = 0; j < mixer.numPorts; ++j) { - sprintf(portNameBuffer, portNameFmt, mixer.ports[j].name, mixerNameBuffer); - portNames->portName[curPortNum++] = strDup(portNameBuffer); - } - } - - return portNames; -} - - -////////// WindowsAudioInputDevice implementation ////////// - -WindowsAudioInputDevice -::WindowsAudioInputDevice(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, - unsigned char numChannels, - unsigned samplingFrequency, - unsigned granularityInMS, - Boolean& success) - : WindowsAudioInputDevice_common(env, inputPortNumber, - bitsPerSample, numChannels, samplingFrequency, granularityInMS), - fCurMixerId(-1) { - success = initialSetInputPort(inputPortNumber); -} - -WindowsAudioInputDevice::~WindowsAudioInputDevice() { - if (fCurMixerId >= 0) ourMixers[fCurMixerId].close(); - - delete[] ourMixers; ourMixers = NULL; - numMixers = numInputPortsTotal = 0; -} - -void WindowsAudioInputDevice::initializeIfNecessary() { - if (ourMixers != NULL) return; // we've already been initialized - numMixers = mixerGetNumDevs(); - ourMixers = new Mixer[numMixers]; - - // Initialize each mixer: - numInputPortsTotal = 0; - for (unsigned i = 0; i < numMixers; ++i) { - Mixer& mixer = ourMixers[i]; - mixer.index = i; - mixer.open(); - if (mixer.hMixer != NULL) { - // This device has a valid mixer. Get information about its ports: - mixer.getPortsInfo(); - mixer.close(); - - if (mixer.numPorts == 0) continue; - - numInputPortsTotal += mixer.numPorts; - } else { - mixer.ports = NULL; - mixer.numPorts = 0; - } - } -} - -Boolean WindowsAudioInputDevice::setInputPort(int portIndex) { - initializeIfNecessary(); - - if (portIndex < 0 || portIndex >= (int)numInputPortsTotal) { // bad index - envir().setResultMsg("Bad input port index\n"); - return False; - } - - // Find the mixer and port that corresponds to "portIndex": - int newMixerId, portWithinMixer, portIndexCount = 0; - for (newMixerId = 0; newMixerId < (int)numMixers; ++newMixerId) { - int prevPortIndexCount = portIndexCount; - portIndexCount += ourMixers[newMixerId].numPorts; - if (portIndexCount > portIndex) { // it's with this mixer - portWithinMixer = portIndex - prevPortIndexCount; - break; - } - } - - // Check that this mixer is allowed: - if (allowedDeviceNames != NULL) { - int i; - for (i = 0; allowedDeviceNames[i] != NULL; ++i) { - if (strncmp(ourMixers[newMixerId].name, allowedDeviceNames[i], - strlen(allowedDeviceNames[i])) == 0) { - // The allowed device name is a prefix of this mixer's name - break; // this mixer is allowed - } - } - if (allowedDeviceNames[i] == NULL) { // this mixer is not on the allowed list - envir().setResultMsg("Access to this audio device is not allowed\n"); - return False; - } - } - - if (newMixerId != fCurMixerId) { - // The mixer has changed, so close the old one and open the new one: - if (fCurMixerId >= 0) ourMixers[fCurMixerId].close(); - fCurMixerId = newMixerId; - ourMixers[fCurMixerId].open(fNumChannels, fSamplingFrequency, fGranularityInMS); - } - if (portIndex != fCurPortIndex) { - // Change the input port: - fCurPortIndex = portIndex; - char const* errReason; - MMRESULT errCode; - if (!ourMixers[newMixerId].enableInputPort(portWithinMixer, errReason, errCode)) { - char resultMsg[100]; - sprintf(resultMsg, "Failed to enable input port: %s failed (0x%08x)\n", errReason, errCode); - envir().setResultMsg(resultMsg); - return False; - } - // Later, may also need to transfer 'gain' to new port ##### - } - return True; -} - -unsigned WindowsAudioInputDevice::numMixers = 0; - -Mixer* WindowsAudioInputDevice::ourMixers = NULL; - -unsigned WindowsAudioInputDevice::numInputPortsTotal = 0; - - -////////// Mixer and AudioInputPort implementation ////////// - -Mixer::Mixer() - : hMixer(NULL), dwRecLineID(0), numPorts(0), ports(NULL) { -} - -Mixer::~Mixer() { - delete[] ports; -} - -void Mixer::open(unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS) { - HMIXER newHMixer = NULL; - do { - MIXERCAPS mc; - if (mixerGetDevCaps(index, &mc, sizeof mc) != MMSYSERR_NOERROR) break; - - // Copy the mixer name: - strncpy(name, mc.szPname, MAXPNAMELEN); - - // Find the correct line for this mixer: - unsigned i, uWavIn; - unsigned nWavIn = waveInGetNumDevs(); - for (i = 0; i < nWavIn; ++i) { - WAVEINCAPS wic; - if (waveInGetDevCaps(i, &wic, sizeof wic) != MMSYSERR_NOERROR) continue; - - MIXERLINE ml; - ml.cbStruct = sizeof ml; - ml.Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN; - strncpy(ml.Target.szPname, wic.szPname, MAXPNAMELEN); - ml.Target.vDriverVersion = wic.vDriverVersion; - ml.Target.wMid = wic.wMid; - ml.Target.wPid = wic.wPid; - - if (mixerGetLineInfo((HMIXEROBJ)index, &ml, MIXER_GETLINEINFOF_TARGETTYPE/*|MIXER_OBJECTF_MIXER*/) == MMSYSERR_NOERROR) { - // this is the right line - uWavIn = i; - dwRecLineID = ml.dwLineID; - break; - } - } - if (i >= nWavIn) break; // error: we couldn't find the right line - - if (mixerOpen(&newHMixer, index, (unsigned long)NULL, (unsigned long)NULL, MIXER_OBJECTF_MIXER) != MMSYSERR_NOERROR) break; - if (newHMixer == NULL) break; - - // Sanity check: re-call "mixerGetDevCaps()" using the mixer device handle: - if (mixerGetDevCaps((UINT)newHMixer, &mc, sizeof mc) != MMSYSERR_NOERROR) break; - if (mc.cDestinations < 1) break; // error: this mixer has no destinations - - if (!WindowsAudioInputDevice_common::openWavInPort(uWavIn, numChannels, samplingFrequency, granularityInMS)) break; - - hMixer = newHMixer; - return; - } while (0); - - // An error occurred: - close(); -} - -void Mixer::open() { - open(1, 8000, 20); -} - -void Mixer::getPortsInfo() { - MIXERCAPS mc; - mixerGetDevCaps((UINT)hMixer, &mc, sizeof mc); - - MIXERLINE mlt; - unsigned i; - for (i = 0; i < mc.cDestinations; ++i) { - memset(&mlt, 0, sizeof mlt); - mlt.cbStruct = sizeof mlt; - mlt.dwDestination = i; - if (mixerGetLineInfo((HMIXEROBJ)hMixer, &mlt, MIXER_GETLINEINFOF_DESTINATION) != MMSYSERR_NOERROR) continue; - if (mlt.dwLineID == dwRecLineID) break; // this is the destination we're interested in - } - ports = new AudioInputPort[mlt.cConnections]; - - numPorts = mlt.cConnections; - for (i = 0; i < numPorts; ++i) { - MIXERLINE mlc; - memcpy(&mlc, &mlt, sizeof mlc); - mlc.dwSource = i; - mixerGetLineInfo((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINEINFOF_SOURCE/*|MIXER_OBJECTF_HMIXER*/); - ports[i].tag = mlc.dwLineID; - ports[i].dwComponentType = mlc.dwComponentType; - strncpy(ports[i].name, mlc.szName, MIXER_LONG_NAME_CHARS); - } - - // Make the microphone the first port in the list: - for (i = 1; i < numPorts; ++i) { -#ifdef OLD_MICROPHONE_TESTING_CODE - if (_strnicmp("mic", ports[i].name, 3) == 0 || - _strnicmp("mik", ports[i].name, 3) == 0) { -#else - if (ports[i].dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) { -#endif - AudioInputPort tmp = ports[0]; - ports[0] = ports[i]; - ports[i] = tmp; - } - } -} - -Boolean Mixer::enableInputPort(unsigned portIndex, char const*& errReason, MMRESULT& errCode) { - errReason = NULL; // unless there's an error - AudioInputPort& port = ports[portIndex]; - - MIXERCONTROL mc; - mc.cMultipleItems = 1; // in case it doesn't get set below - MIXERLINECONTROLS mlc; -#if 0 // the following doesn't seem to be needed, and can fail: - mlc.cbStruct = sizeof mlc; - mlc.pamxctrl = &mc; - mlc.cbmxctrl = sizeof (MIXERCONTROL); - mlc.dwLineID = port.tag; - mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; - if ((errCode = mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { - errReason = "mixerGetLineControls()"; - return False; - } -#endif - - MIXERLINE ml; - memset(&ml, 0, sizeof (MIXERLINE)); - ml.cbStruct = sizeof (MIXERLINE); - ml.dwLineID = port.tag; - if ((errCode = mixerGetLineInfo((HMIXEROBJ)hMixer, &ml, MIXER_GETLINEINFOF_LINEID)) != MMSYSERR_NOERROR) { - errReason = "mixerGetLineInfo()1"; - return False; - } - - char portname[MIXER_LONG_NAME_CHARS+1]; - strncpy(portname, ml.szName, MIXER_LONG_NAME_CHARS); - - memset(&ml, 0, sizeof (MIXERLINE)); - ml.cbStruct = sizeof (MIXERLINE); - ml.dwLineID = dwRecLineID; - if ((errCode = mixerGetLineInfo((HMIXEROBJ)hMixer, &ml, MIXER_GETLINEINFOF_LINEID/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { - errReason = "mixerGetLineInfo()2"; - return False; - } - - // Get Mixer/MUX control information (need control id to set and get control details) - mlc.cbStruct = sizeof mlc; - mlc.dwLineID = ml.dwLineID; - mlc.cControls = 1; - mc.cbStruct = sizeof mc; // Needed???##### - mc.dwControlID = 0xDEADBEEF; // For testing ##### - mlc.pamxctrl = &mc; - mlc.cbmxctrl = sizeof mc; - mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX; // Single Select - if ((errCode = mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { - mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MIXER; // Multiple Select - mixerGetLineControls((HMIXEROBJ)hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE/*|MIXER_OBJECTF_HMIXER*/); - } - - unsigned matchLine = 0; - if (mc.cMultipleItems > 1) { - // Before getting control, we need to know which line to grab. - // We figure this out by listing the lines, and comparing names: - MIXERCONTROLDETAILS mcd; - mcd.cbStruct = sizeof mcd; - mcd.cChannels = ml.cChannels; - mcd.cMultipleItems = mc.cMultipleItems; - MIXERCONTROLDETAILS_LISTTEXT* mcdlText = new MIXERCONTROLDETAILS_LISTTEXT[mc.cMultipleItems]; - mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_LISTTEXT); - mcd.paDetails = mcdlText; - - if (mc.dwControlID != 0xDEADBEEF) { // we know the control id for real - mcd.dwControlID = mc.dwControlID; - if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_LISTTEXT/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { - delete[] mcdlText; - errReason = "mixerGetControlDetails()1"; - return False; - } - } else { - // Hack: We couldn't find a MUX or MIXER control, so try to guess the control id: - for (mc.dwControlID = 0; mc.dwControlID < 32; ++mc.dwControlID) { - mcd.dwControlID = mc.dwControlID; - if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_LISTTEXT/*|MIXER_OBJECTF_HMIXER*/)) == MMSYSERR_NOERROR) break; - } - if (mc.dwControlID == 32) { // unable to guess mux/mixer control id - delete[] mcdlText; - errReason = "mixerGetControlDetails()2"; - return False; - } - } - - for (unsigned i = 0; i < mcd.cMultipleItems; ++i) { - if (strcmp(mcdlText[i].szName, portname) == 0) { - matchLine = i; - break; - } - } - delete[] mcdlText; - } - - // Now get control itself: - MIXERCONTROLDETAILS mcd; - mcd.cbStruct = sizeof mcd; - mcd.dwControlID = mc.dwControlID; - mcd.cChannels = ml.cChannels; - mcd.cMultipleItems = mc.cMultipleItems; - MIXERCONTROLDETAILS_BOOLEAN* mcdbState = new MIXERCONTROLDETAILS_BOOLEAN[mc.cMultipleItems]; - mcd.paDetails = mcdbState; - mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_BOOLEAN); - - if ((errCode = mixerGetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_GETCONTROLDETAILSF_VALUE/*|MIXER_OBJECTF_HMIXER*/)) != MMSYSERR_NOERROR) { - delete[] mcdbState; - errReason = "mixerGetControlDetails()3"; - return False; - } - - for (unsigned j = 0; j < mcd.cMultipleItems; ++j) { - mcdbState[j].fValue = (j == matchLine); - } - - if ((errCode = mixerSetControlDetails((HMIXEROBJ)hMixer, &mcd, MIXER_OBJECTF_HMIXER)) != MMSYSERR_NOERROR) { - delete[] mcdbState; - errReason = "mixerSetControlDetails()"; - return False; - } - delete[] mcdbState; - - return True; -} - - -void Mixer::close() { - WindowsAudioInputDevice_common::waveIn_close(); - if (hMixer != NULL) mixerClose(hMixer); - hMixer = NULL; dwRecLineID = 0; -} diff --git a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_mixer.hh b/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_mixer.hh deleted file mode 100644 index e62a7cd3e7a..00000000000 --- a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_mixer.hh +++ /dev/null @@ -1,57 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Windows implementation of a generic audio input device -// This version uses Windows' built-in software mixer. -// C++ header -// -// To use this, call "AudioInputDevice::createNew()". -// You can also call "AudioInputDevice::getPortNames()" to get a list -// of port names. - -#ifndef _WINDOWS_AUDIO_INPUT_DEVICE_MIXER_HH -#define _WINDOWS_AUDIO_INPUT_DEVICE_MIXER_HH - -#ifndef _WINDOWS_AUDIO_INPUT_DEVICE_COMMON_HH -#include "WindowsAudioInputDevice_common.hh" -#endif - -class WindowsAudioInputDevice: public WindowsAudioInputDevice_common { -private: - friend class AudioInputDevice; - WindowsAudioInputDevice(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, unsigned char numChannels, - unsigned samplingFrequency, unsigned granularityInMS, - Boolean& success); - // called only by createNew() - - virtual ~WindowsAudioInputDevice(); - - static void initializeIfNecessary(); - -private: - // redefined virtual functions: - virtual Boolean setInputPort(int portIndex); - -private: - static unsigned numMixers; - static class Mixer* ourMixers; - static unsigned numInputPortsTotal; - - int fCurMixerId; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_noMixer.cpp b/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_noMixer.cpp deleted file mode 100644 index 4b554d22211..00000000000 --- a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_noMixer.cpp +++ /dev/null @@ -1,174 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 2001-2004 Live Networks, Inc. All rights reserved. -// Windows implementation of a generic audio input device -// This version does not use Windows' built-in software mixer. -// Implementation - -#include - -////////// AudioInputPort definition ////////// - -class AudioInputPort { -public: - void open(unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS); - void open(); // open with default parameters - void close(); - -public: - int index; - char name[MAXPNAMELEN]; -}; - - -////////// AudioInputDevice (remaining) implementation ////////// - -AudioInputDevice* -AudioInputDevice::createNew(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, - unsigned char numChannels, - unsigned samplingFrequency, - unsigned granularityInMS) { - Boolean success; - WindowsAudioInputDevice* newSource - = new WindowsAudioInputDevice(env, inputPortNumber, - bitsPerSample, numChannels, - samplingFrequency, granularityInMS, - success); - if (!success) {delete newSource; newSource = NULL;} - - return newSource; -} - -AudioPortNames* AudioInputDevice::getPortNames() { - WindowsAudioInputDevice::initializeIfNecessary(); - - AudioPortNames* portNames = new AudioPortNames; - portNames->numPorts = WindowsAudioInputDevice::numAudioInputPorts; - portNames->portName = new char*[WindowsAudioInputDevice::numAudioInputPorts]; - - for (unsigned i = 0; i < WindowsAudioInputDevice::numAudioInputPorts; ++i) { - AudioInputPort& audioInputPort = WindowsAudioInputDevice::ourAudioInputPorts[i]; - - portNames->portName[i] = strDup(audioInputPort.name); - } - - return portNames; -} - - -////////// WindowsAudioInputDevice implementation ////////// - -WindowsAudioInputDevice -::WindowsAudioInputDevice(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, - unsigned char numChannels, - unsigned samplingFrequency, - unsigned granularityInMS, - Boolean& success) - : WindowsAudioInputDevice_common(env, inputPortNumber, - bitsPerSample, numChannels, samplingFrequency, granularityInMS) { - success = initialSetInputPort(inputPortNumber); -} - -WindowsAudioInputDevice::~WindowsAudioInputDevice() { - if (fCurPortIndex >= 0) ourAudioInputPorts[fCurPortIndex].close(); - - delete[] ourAudioInputPorts; ourAudioInputPorts = NULL; - numAudioInputPorts = 0; -} - -void WindowsAudioInputDevice::initializeIfNecessary() { - if (ourAudioInputPorts != NULL) return; // we've already been initialized - numAudioInputPorts = waveInGetNumDevs(); - ourAudioInputPorts = new AudioInputPort[numAudioInputPorts]; - - // Initialize each audio input port - for (unsigned i = 0; i < numAudioInputPorts; ++i) { - AudioInputPort& port = ourAudioInputPorts[i]; - port.index = i; - port.open(); // to set the port name - port.close(); - } -} - -Boolean WindowsAudioInputDevice::setInputPort(int portIndex) { - initializeIfNecessary(); - - if (portIndex < 0 || portIndex >= (int)numAudioInputPorts) { // bad index - envir().setResultMsg("Bad input port index\n"); - return False; - } - - // Check that this port is allowed: - if (allowedDeviceNames != NULL) { - int i; - for (i = 0; allowedDeviceNames[i] != NULL; ++i) { - if (strncmp(ourAudioInputPorts[portIndex].name, allowedDeviceNames[i], - strlen(allowedDeviceNames[i])) == 0) { - // The allowed device name is a prefix of this port's name - break; // this port is allowed - } - } - if (allowedDeviceNames[i] == NULL) { // this port is not on the allowed list - envir().setResultMsg("Access to this audio device is not allowed\n"); - return False; - } - } - - if (portIndex != fCurPortIndex) { - // The port has changed, so close the old one and open the new one: - if (fCurPortIndex >= 0) ourAudioInputPorts[fCurPortIndex].close();; - fCurPortIndex = portIndex; - ourAudioInputPorts[fCurPortIndex].open(fNumChannels, fSamplingFrequency, fGranularityInMS); - } - fCurPortIndex = portIndex; - return True; -} - -unsigned WindowsAudioInputDevice::numAudioInputPorts = 0; - -AudioInputPort* WindowsAudioInputDevice::ourAudioInputPorts = NULL; - - -////////// AudioInputPort implementation ////////// - -void AudioInputPort::open(unsigned numChannels, unsigned samplingFrequency, unsigned granularityInMS) { - do { - // Get the port name: - WAVEINCAPS wic; - if (waveInGetDevCaps(index, &wic, sizeof wic) != MMSYSERR_NOERROR) { - name[0] = '\0'; - break; - } - strncpy(name, wic.szPname, MAXPNAMELEN); - - if (!WindowsAudioInputDevice_common::openWavInPort(index, numChannels, samplingFrequency, granularityInMS)) break; - - return; - } while (0); - - // An error occurred: - close(); -} - -void AudioInputPort::open() { - open(1, 8000, 20); -} - -void AudioInputPort::close() { - WindowsAudioInputDevice_common::waveIn_close(); -} diff --git a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_noMixer.hh b/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_noMixer.hh deleted file mode 100644 index 6b8a0a3e6f0..00000000000 --- a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/WindowsAudioInputDevice_noMixer.hh +++ /dev/null @@ -1,54 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Windows implementation of a generic audio input device -// This version does not use Windows' built-in software mixer. -// C++ header -// -// To use this, call "AudioInputDevice::createNew()". -// You can also call "AudioInputDevice::getPortNames()" to get a list -// of port names. - -#ifndef _WINDOWS_AUDIO_INPUT_DEVICE_NOMIXER_HH -#define _WINDOWS_AUDIO_INPUT_DEVICE_NOMIXER_HH - -#ifndef _WINDOWS_AUDIO_INPUT_DEVICE_COMMON_HH -#include "WindowsAudioInputDevice_common.hh" -#endif - -class WindowsAudioInputDevice: public WindowsAudioInputDevice_common { -private: - friend class AudioInputDevice; - WindowsAudioInputDevice(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, unsigned char numChannels, - unsigned samplingFrequency, unsigned granularityInMS, - Boolean& success); - // called only by createNew() - - virtual ~WindowsAudioInputDevice(); - - static void initializeIfNecessary(); - -private: - // redefined virtual functions: - virtual Boolean setInputPort(int portIndex); - -private: - static unsigned numAudioInputPorts; - static class AudioInputPort* ourAudioInputPorts; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/showAudioInputPorts.cpp b/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/showAudioInputPorts.cpp deleted file mode 100644 index b425571597b..00000000000 --- a/mythtv/libs/libmythlivemedia/WindowsAudioInputDevice/showAudioInputPorts.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2003, Live Networks, Inc. All rights reserved -// A program that prints out this computer's audio input ports - -#include "AudioInputDevice.hh" -#include - -int main(int argc, char** argv) { - AudioPortNames* portNames = AudioInputDevice::getPortNames(); - if (portNames == NULL) { - fprintf(stderr, "AudioInputDevice::getPortNames() failed!\n"); - exit(1); - } - - printf("%d available audio input ports:\n", portNames->numPorts); - for (unsigned i = 0; i < portNames->numPorts; ++i) { - printf("%d\t%s\n", i, portNames->portName[i]); - } - - return 0; -} diff --git a/mythtv/libs/libmythlivemedia/groupsock/COPYING b/mythtv/libs/libmythlivemedia/groupsock/COPYING deleted file mode 100644 index 3b204400cf3..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/COPYING +++ /dev/null @@ -1,458 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS diff --git a/mythtv/libs/libmythlivemedia/groupsock/GroupEId.cpp b/mythtv/libs/libmythlivemedia/groupsock/GroupEId.cpp deleted file mode 100644 index 10509bd5da5..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/GroupEId.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-1997, Live Networks, Inc. All rights reserved -// "Group Endpoint Id" -// Implementation - -#include "GroupEId.hh" -#include "strDup.hh" -#include - -////////// Scope ////////// - -void Scope::assign(u_int8_t ttl, const char* publicKey) { - fTTL = ttl; - - fPublicKey = strDup(publicKey == NULL ? "nokey" : publicKey); -} - -void Scope::clean() { - delete[] fPublicKey; - fPublicKey = NULL; -} - - -Scope::Scope(u_int8_t ttl, const char* publicKey) { - assign(ttl, publicKey); -} - -Scope::Scope(const Scope& orig) { - assign(orig.ttl(), orig.publicKey()); -} - -Scope& Scope::operator=(const Scope& rightSide) { - if (&rightSide != this) { - if (publicKey() == NULL - || strcmp(publicKey(), rightSide.publicKey()) != 0) { - clean(); - assign(rightSide.ttl(), rightSide.publicKey()); - } else { // need to assign TTL only - fTTL = rightSide.ttl(); - } - } - - return *this; -} - -Scope::~Scope() { - clean(); -} - -unsigned Scope::publicKeySize() const { - return fPublicKey == NULL ? 0 : strlen(fPublicKey); -} - -////////// GroupEId ////////// - -GroupEId::GroupEId(struct in_addr const& groupAddr, - portNumBits portNum, Scope const& scope, - unsigned numSuccessiveGroupAddrs) { - struct in_addr sourceFilterAddr; - sourceFilterAddr.s_addr = ~0; // indicates no source filter - - init(groupAddr, sourceFilterAddr, portNum, scope, numSuccessiveGroupAddrs); -} - -GroupEId::GroupEId(struct in_addr const& groupAddr, - struct in_addr const& sourceFilterAddr, - portNumBits portNum, - unsigned numSuccessiveGroupAddrs) { - init(groupAddr, sourceFilterAddr, portNum, 255, numSuccessiveGroupAddrs); -} - -GroupEId::GroupEId() { -} - -Boolean GroupEId::isSSM() const { - return fSourceFilterAddress.s_addr != netAddressBits(~0); -} - - -void GroupEId::init(struct in_addr const& groupAddr, - struct in_addr const& sourceFilterAddr, - portNumBits portNum, - Scope const& scope, - unsigned numSuccessiveGroupAddrs) { - fGroupAddress = groupAddr; - fSourceFilterAddress = sourceFilterAddr; - fNumSuccessiveGroupAddrs = numSuccessiveGroupAddrs; - fPortNum = portNum; - fScope = scope; -} diff --git a/mythtv/libs/libmythlivemedia/groupsock/Groupsock.cpp b/mythtv/libs/libmythlivemedia/groupsock/Groupsock.cpp deleted file mode 100644 index 8a50435a8b9..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/Groupsock.cpp +++ /dev/null @@ -1,643 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// 'Group sockets' -// Implementation - -#include "Groupsock.hh" -#include "GroupsockHelper.hh" -//##### Eventually fix the following #include; we shouldn't know about tunnels -#include "TunnelEncaps.hh" - -#ifndef NO_STRSTREAM -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(__MINGW32__) -#include -#else -#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) -#include -#else -#include -#endif -#endif -#endif -#include - -///////// OutputSocket ////////// - -OutputSocket::OutputSocket(UsageEnvironment& env) - : Socket(env, 0 /* let kernel choose port */), - fSourcePort(0), fLastSentTTL(0) { -} - -OutputSocket::OutputSocket(UsageEnvironment& env, Port port) - : Socket(env, port), - fSourcePort(0), fLastSentTTL(0) { -} - -OutputSocket::~OutputSocket() { -} - -Boolean OutputSocket::write(netAddressBits address, Port port, u_int8_t ttl, - unsigned char* buffer, unsigned bufferSize) { - if (ttl == fLastSentTTL) { - // Optimization: So we don't do a 'set TTL' system call again - ttl = 0; - } else { - fLastSentTTL = ttl; - } - struct in_addr destAddr; destAddr.s_addr = address; - if (!writeSocket(env(), socketNum(), destAddr, port, ttl, - buffer, bufferSize)) - return False; - - if (sourcePortNum() == 0) { - // Now that we've sent a packet, we can find out what the - // kernel chose as our ephemeral source port number: - if (!getSourcePort(env(), socketNum(), fSourcePort)) { - if (DebugLevel >= 1) - env() << *this - << ": failed to get source port: " - << env().getResultMsg() << "\n"; - return False; - } - } - - return True; -} - -// By default, we don't do reads: -Boolean OutputSocket -::handleRead(unsigned char* /*buffer*/, unsigned /*bufferMaxSize*/, - unsigned& /*bytesRead*/, struct sockaddr_in& /*fromAddress*/) { - return True; -} - - -///////// destRecord ////////// - -destRecord -::destRecord(struct in_addr const& addr, Port const& port, u_int8_t ttl, - destRecord* next) - : fNext(next), fGroupEId(addr, port.num(), ttl), fPort(port) { -} - -destRecord::~destRecord() { - delete fNext; -} - - -///////// Groupsock ////////// - -NetInterfaceTrafficStats Groupsock::statsIncoming; -NetInterfaceTrafficStats Groupsock::statsOutgoing; -NetInterfaceTrafficStats Groupsock::statsRelayedIncoming; -NetInterfaceTrafficStats Groupsock::statsRelayedOutgoing; - -// Constructor for a source-independent multicast group -Groupsock::Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr, - Port port, u_int8_t ttl) - : OutputSocket(env, port), - deleteIfNoMembers(False), isSlave(False), - fIncomingGroupEId(groupAddr, port.num(), ttl), fDests(NULL), fTTL(ttl) { - addDestination(groupAddr, port); - - if (!socketJoinGroup(env, socketNum(), groupAddr.s_addr)) { - if (DebugLevel >= 1) { - env << *this << ": failed to join group: " - << env.getResultMsg() << "\n"; - } - } - - // Make sure we can get our source address: - if (ourSourceAddressForMulticast(env) == 0) { - if (DebugLevel >= 0) { // this is a fatal error - env << "Unable to determine our source address: " - << env.getResultMsg() << "\n"; - } - } - - if (DebugLevel >= 2) env << *this << ": created\n"; -} - -// Constructor for a source-specific multicast group -Groupsock::Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr, - struct in_addr const& sourceFilterAddr, - Port port) - : OutputSocket(env, port), - deleteIfNoMembers(False), isSlave(False), - fIncomingGroupEId(groupAddr, sourceFilterAddr, port.num()), - fDests(NULL), fTTL(255) { - addDestination(groupAddr, port); - - // First try a SSM join. If that fails, try a regular join: - if (!socketJoinGroupSSM(env, socketNum(), groupAddr.s_addr, - sourceFilterAddr.s_addr)) { - if (DebugLevel >= 3) { - env << *this << ": SSM join failed: " - << env.getResultMsg(); - env << " - trying regular join instead\n"; - } - if (!socketJoinGroup(env, socketNum(), groupAddr.s_addr)) { - if (DebugLevel >= 1) { - env << *this << ": failed to join group: " - << env.getResultMsg() << "\n"; - } - } - } - - if (DebugLevel >= 2) env << *this << ": created\n"; -} - -Groupsock::~Groupsock() { - if (isSSM()) { - if (!socketLeaveGroupSSM(env(), socketNum(), groupAddress().s_addr, - sourceFilterAddress().s_addr)) { - socketLeaveGroup(env(), socketNum(), groupAddress().s_addr); - } - } else { - socketLeaveGroup(env(), socketNum(), groupAddress().s_addr); - } - - delete fDests; - - if (DebugLevel >= 2) env() << *this << ": deleting\n"; -} - -void -Groupsock::changeDestinationParameters(struct in_addr const& newDestAddr, - Port newDestPort, int newDestTTL) { - if (fDests == NULL) return; - - struct in_addr destAddr = fDests->fGroupEId.groupAddress(); - if (newDestAddr.s_addr != 0) { - if (newDestAddr.s_addr != destAddr.s_addr - && IsMulticastAddress(newDestAddr.s_addr)) { - // If the new destination is a multicast address, then we assume that - // we want to join it also. (If this is not in fact the case, then - // call "multicastSendOnly()" afterwards.) - socketLeaveGroup(env(), socketNum(), destAddr.s_addr); - socketJoinGroup(env(), socketNum(), newDestAddr.s_addr); - } - destAddr.s_addr = newDestAddr.s_addr; - } - - portNumBits destPortNum = fDests->fGroupEId.portNum(); - if (newDestPort.num() != 0) { - if (newDestPort.num() != destPortNum - && IsMulticastAddress(destAddr.s_addr)) { - // Also bind to the new port number: - changePort(newDestPort); - // And rejoin the multicast group: - socketJoinGroup(env(), socketNum(), destAddr.s_addr); - } - destPortNum = newDestPort.num(); - fDests->fPort = newDestPort; - } - - u_int8_t destTTL = ttl(); - if (newDestTTL != ~0) destTTL = (u_int8_t)newDestTTL; - - fDests->fGroupEId = GroupEId(destAddr, destPortNum, destTTL); -} - -void Groupsock::addDestination(struct in_addr const& addr, Port const& port) { - // Check whether this destination is already known: - for (destRecord* dests = fDests; dests != NULL; dests = dests->fNext) { - if (addr.s_addr == dests->fGroupEId.groupAddress().s_addr - && port.num() == dests->fPort.num()) { - return; - } - } - - fDests = new destRecord(addr, port, ttl(), fDests); -} - -void Groupsock::removeDestination(struct in_addr const& addr, Port const& port) { - for (destRecord** destsPtr = &fDests; *destsPtr != NULL; - destsPtr = &((*destsPtr)->fNext)) { - if (addr.s_addr == (*destsPtr)->fGroupEId.groupAddress().s_addr - && port.num() == (*destsPtr)->fPort.num()) { - // Remove the record pointed to by *destsPtr : - destRecord* next = (*destsPtr)->fNext; - (*destsPtr)->fNext = NULL; - delete (*destsPtr); - *destsPtr = next; - return; - } - } -} - -void Groupsock::removeAllDestinations() { - delete fDests; fDests = NULL; -} - -void Groupsock::multicastSendOnly() { - socketLeaveGroup(env(), socketNum(), fIncomingGroupEId.groupAddress().s_addr); - for (destRecord* dests = fDests; dests != NULL; dests = dests->fNext) { - socketLeaveGroup(env(), socketNum(), dests->fGroupEId.groupAddress().s_addr); - } -} - -Boolean Groupsock::output(UsageEnvironment& env, u_int8_t ttlToSend, - unsigned char* buffer, unsigned bufferSize, - DirectedNetInterface* interfaceNotToFwdBackTo) { - do { - // First, do the datagram send, to each destination: - Boolean writeSuccess = True; - for (destRecord* dests = fDests; dests != NULL; dests = dests->fNext) { - if (!write(dests->fGroupEId.groupAddress().s_addr, dests->fPort, ttlToSend, - buffer, bufferSize)) { - writeSuccess = False; - break; - } - } - if (!writeSuccess) break; - statsOutgoing.countPacket(bufferSize); - statsGroupOutgoing.countPacket(bufferSize); - - // Then, forward to our members: - int numMembers = - outputToAllMembersExcept(interfaceNotToFwdBackTo, - ttlToSend, buffer, bufferSize, - ourSourceAddressForMulticast(env)); - if (numMembers < 0) break; - - if (DebugLevel >= 3) { - env << *this << ": wrote " << bufferSize << " bytes, ttl " - << (unsigned)ttlToSend; - if (numMembers > 0) { - env << "; relayed to " << numMembers << " members"; - } - env << "\n"; - } - return True; - } while (0); - - if (DebugLevel >= 0) { // this is a fatal error - env.setResultMsg("Groupsock write failed: ", env.getResultMsg()); - } - return False; -} - -Boolean Groupsock::handleRead(unsigned char* buffer, unsigned bufferMaxSize, - unsigned& bytesRead, - struct sockaddr_in& fromAddress) { - // Read data from the socket, and relay it across any attached tunnels - //##### later make this code more general - independent of tunnels - - bytesRead = 0; - - int maxBytesToRead = bufferMaxSize - TunnelEncapsulationTrailerMaxSize; - int numBytes = readSocket(env(), socketNum(), - buffer, maxBytesToRead, fromAddress); - if (numBytes < 0) { - if (DebugLevel >= 0) { // this is a fatal error - env().setResultMsg("Groupsock read failed: ", - env().getResultMsg()); - } - return False; - } - - // If we're a SSM group, make sure the source address matches: - if (isSSM() - && fromAddress.sin_addr.s_addr != sourceFilterAddress().s_addr) { - return True; - } - - // We'll handle this data. - // Also write it (with the encapsulation trailer) to each member, - // unless the packet was originally sent by us to begin with. - bytesRead = numBytes; - - int numMembers = 0; - if (!wasLoopedBackFromUs(env(), fromAddress)) { - statsIncoming.countPacket(numBytes); - statsGroupIncoming.countPacket(numBytes); - numMembers = - outputToAllMembersExcept(NULL, ttl(), - buffer, bytesRead, - fromAddress.sin_addr.s_addr); - if (numMembers > 0) { - statsRelayedIncoming.countPacket(numBytes); - statsGroupRelayedIncoming.countPacket(numBytes); - } - } - if (DebugLevel >= 3) { - env() << *this << ": read " << bytesRead << " bytes from "; - env() << our_inet_ntoa(fromAddress.sin_addr); - if (numMembers > 0) { - env() << "; relayed to " << numMembers << " members"; - } - env() << "\n"; - } - - return True; -} - -Boolean Groupsock::wasLoopedBackFromUs(UsageEnvironment& env, - struct sockaddr_in& fromAddress) { - if (fromAddress.sin_addr.s_addr - == ourSourceAddressForMulticast(env)) { - if (fromAddress.sin_port == sourcePortNum()) { -#ifdef DEBUG_LOOPBACK_CHECKING - if (DebugLevel >= 3) { - env() << *this << ": got looped-back packet\n"; - } -#endif - return True; - } - } - - return False; -} - -int Groupsock::outputToAllMembersExcept(DirectedNetInterface* exceptInterface, - u_int8_t ttlToFwd, - unsigned char* data, unsigned size, - netAddressBits sourceAddr) { - // Don't forward TTL-0 packets - if (ttlToFwd == 0) return 0; - - DirectedNetInterfaceSet::Iterator iter(members()); - unsigned numMembers = 0; - DirectedNetInterface* interf; - while ((interf = iter.next()) != NULL) { - // Check whether we've asked to exclude this interface: - if (interf == exceptInterface) - continue; - - // Check that the packet's source address makes it OK to - // be relayed across this interface: - UsageEnvironment& saveEnv = env(); - // because the following call may delete "this" - if (!interf->SourceAddrOKForRelaying(saveEnv, sourceAddr)) { - if (strcmp(saveEnv.getResultMsg(), "") != 0) { - // Treat this as a fatal error - return -1; - } else { - continue; - } - } - - if (numMembers == 0) { - // We know that we're going to forward to at least one - // member, so fill in the tunnel encapsulation trailer. - // (Note: Allow for it not being 4-byte-aligned.) - TunnelEncapsulationTrailer* trailerInPacket - = (TunnelEncapsulationTrailer*)&data[size]; - TunnelEncapsulationTrailer* trailer; - - Boolean misaligned = ((unsigned long)trailerInPacket & 3) != 0; - unsigned trailerOffset; - u_int8_t tunnelCmd; - if (isSSM()) { - // add an 'auxilliary address' before the trailer - trailerOffset = TunnelEncapsulationTrailerAuxSize; - tunnelCmd = TunnelDataAuxCmd; - } else { - trailerOffset = 0; - tunnelCmd = TunnelDataCmd; - } - unsigned trailerSize = TunnelEncapsulationTrailerSize + trailerOffset; - unsigned tmpTr[TunnelEncapsulationTrailerMaxSize]; - if (misaligned) { - trailer = (TunnelEncapsulationTrailer*)&tmpTr; - } else { - trailer = trailerInPacket; - } - trailer += trailerOffset; - - if (fDests != NULL) { - trailer->address() = fDests->fGroupEId.groupAddress().s_addr; - trailer->port() = fDests->fPort; // structure copy, outputs in network order - } - trailer->ttl() = ttlToFwd; - trailer->command() = tunnelCmd; - - if (isSSM()) { - trailer->auxAddress() = sourceFilterAddress().s_addr; - } - - if (misaligned) { - memmove(trailerInPacket, trailer-trailerOffset, trailerSize); - } - - size += trailerSize; - } - - interf->write(data, size); - ++numMembers; - } - - return numMembers; -} - -UsageEnvironment& operator<<(UsageEnvironment& s, const Groupsock& g) { - UsageEnvironment& s1 = s << timestampString() << " Groupsock(" - << g.socketNum() << ": " - << our_inet_ntoa(g.groupAddress()) - << ", " << g.port() << ", "; - if (g.isSSM()) { - return s1 << "SSM source: " - << our_inet_ntoa(g.sourceFilterAddress()) << ")"; - } else { - return s1 << (unsigned)(g.ttl()) << ")"; - } -} - - -////////// GroupsockLookupTable ////////// - - -// A hash table used to index Groupsocks by socket number. - -static HashTable* getSocketTable(UsageEnvironment& env) { - if (env.groupsockPriv == NULL) { // We need to create it - env.groupsockPriv = HashTable::create(ONE_WORD_HASH_KEYS); - } - return (HashTable*)(env.groupsockPriv); -} - -static Boolean unsetGroupsockBySocket(Groupsock const* groupsock) { - do { - if (groupsock == NULL) break; - - int sock = groupsock->socketNum(); - // Make sure "sock" is in bounds: - if (sock < 0) break; - - HashTable* sockets = getSocketTable(groupsock->env()); - if (sockets == NULL) break; - - Groupsock* gs = (Groupsock*)sockets->Lookup((char*)(long)sock); - if (gs == NULL || gs != groupsock) break; - sockets->Remove((char*)(long)sock); - - if (sockets->IsEmpty()) { - // We can also delete the table (to reclaim space): - delete sockets; - (gs->env()).groupsockPriv = NULL; - } - - return True; - } while (0); - - return False; -} - -static Boolean setGroupsockBySocket(UsageEnvironment& env, int sock, - Groupsock* groupsock) { - do { - // Make sure the "sock" parameter is in bounds: - if (sock < 0) { - char buf[100]; - sprintf(buf, "trying to use bad socket (%d)", sock); - env.setResultMsg(buf); - break; - } - - HashTable* sockets = getSocketTable(env); - if (sockets == NULL) break; - - // Make sure we're not replacing an existing Groupsock - // That shouldn't happen - Boolean alreadyExists - = (sockets->Lookup((char*)(long)sock) != 0); - if (alreadyExists) { - char buf[100]; - sprintf(buf, - "Attempting to replace an existing socket (%d", - sock); - env.setResultMsg(buf); - break; - } - - sockets->Add((char*)(long)sock, groupsock); - return True; - } while (0); - - return False; -} - -static Groupsock* getGroupsockBySocket(UsageEnvironment& env, int sock) { - do { - // Make sure the "sock" parameter is in bounds: - if (sock < 0) break; - - HashTable* sockets = getSocketTable(env); - if (sockets == NULL) break; - - return (Groupsock*)sockets->Lookup((char*)(long)sock); - } while (0); - - return NULL; -} - -Groupsock* -GroupsockLookupTable::Fetch(UsageEnvironment& env, - netAddressBits groupAddress, - Port port, u_int8_t ttl, - Boolean& isNew) { - isNew = False; - Groupsock* groupsock; - do { - groupsock = (Groupsock*) fTable.Lookup(groupAddress, (~0), port); - if (groupsock == NULL) { // we need to create one: - groupsock = AddNew(env, groupAddress, (~0), port, ttl); - if (groupsock == NULL) break; - isNew = True; - } - } while (0); - - return groupsock; -} - -Groupsock* -GroupsockLookupTable::Fetch(UsageEnvironment& env, - netAddressBits groupAddress, - netAddressBits sourceFilterAddr, Port port, - Boolean& isNew) { - isNew = False; - Groupsock* groupsock; - do { - groupsock - = (Groupsock*) fTable.Lookup(groupAddress, sourceFilterAddr, port); - if (groupsock == NULL) { // we need to create one: - groupsock = AddNew(env, groupAddress, sourceFilterAddr, port, 0); - if (groupsock == NULL) break; - isNew = True; - } - } while (0); - - return groupsock; -} - -Groupsock* -GroupsockLookupTable::Lookup(netAddressBits groupAddress, Port port) { - return (Groupsock*) fTable.Lookup(groupAddress, (~0), port); -} - -Groupsock* -GroupsockLookupTable::Lookup(netAddressBits groupAddress, - netAddressBits sourceFilterAddr, Port port) { - return (Groupsock*) fTable.Lookup(groupAddress, sourceFilterAddr, port); -} - -Groupsock* GroupsockLookupTable::Lookup(UsageEnvironment& env, int sock) { - return getGroupsockBySocket(env, sock); -} - -Boolean GroupsockLookupTable::Remove(Groupsock const* groupsock) { - unsetGroupsockBySocket(groupsock); - return fTable.Remove(groupsock->groupAddress().s_addr, - groupsock->sourceFilterAddress().s_addr, - groupsock->port()); -} - -Groupsock* GroupsockLookupTable::AddNew(UsageEnvironment& env, - netAddressBits groupAddress, - netAddressBits sourceFilterAddress, - Port port, u_int8_t ttl) { - Groupsock* groupsock; - do { - struct in_addr groupAddr; groupAddr.s_addr = groupAddress; - if (sourceFilterAddress == netAddressBits(~0)) { - // regular, ISM groupsock - groupsock = new Groupsock(env, groupAddr, port, ttl); - } else { - // SSM groupsock - struct in_addr sourceFilterAddr; - sourceFilterAddr.s_addr = sourceFilterAddress; - groupsock = new Groupsock(env, groupAddr, sourceFilterAddr, port); - } - - if (groupsock == NULL || groupsock->socketNum() < 0) break; - - if (!setGroupsockBySocket(env, groupsock->socketNum(), groupsock)) break; - - fTable.Add(groupAddress, sourceFilterAddress, port, (void*)groupsock); - } while (0); - - return groupsock; -} - -GroupsockLookupTable::Iterator::Iterator(GroupsockLookupTable& groupsocks) - : fIter(AddressPortLookupTable::Iterator(groupsocks.fTable)) { -} - -Groupsock* GroupsockLookupTable::Iterator::next() { - return (Groupsock*) fIter.next(); -}; diff --git a/mythtv/libs/libmythlivemedia/groupsock/GroupsockHelper.cpp b/mythtv/libs/libmythlivemedia/groupsock/GroupsockHelper.cpp deleted file mode 100644 index 6992f344f7b..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/GroupsockHelper.cpp +++ /dev/null @@ -1,733 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Helper routines to implement 'group sockets' -// Implementation - -#include "GroupsockHelper.hh" - -#if defined(__WIN32__) || defined(_WIN32) -#include -extern "C" int initializeWinsockIfNecessary(); -#else -#include -#include -#include -#define initializeWinsockIfNecessary() 1 -#endif -#include - -// By default, use INADDR_ANY for the sending and receiving interfaces: -netAddressBits SendingInterfaceAddr = INADDR_ANY; -netAddressBits ReceivingInterfaceAddr = INADDR_ANY; -netAddressBits ReceivingSocketAddr = INADDR_ANY; - -static void socketErr(UsageEnvironment& env, char* errorMsg) { - env.setResultErrMsg(errorMsg); -} - -int setupDatagramSocket(UsageEnvironment& env, Port port, -#ifdef IP_MULTICAST_LOOP - Boolean setLoopback -#else - Boolean -#endif -) { - if (!initializeWinsockIfNecessary()) { - socketErr(env, "Failed to initialize 'winsock': "); - return -1; - } - - int newSocket = socket(AF_INET, SOCK_DGRAM, 0); - if (newSocket < 0) { - socketErr(env, "unable to create datagram socket: "); - return newSocket; - } - - const int reuseFlag = 1; - if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, - (const char*)&reuseFlag, sizeof reuseFlag) < 0) { - socketErr(env, "setsockopt(SO_REUSEADDR) error: "); - closeSocket(newSocket); - return -1; - } - -#if defined(__WIN32__) || defined(_WIN32) - // Windoze doesn't handle SO_REUSEPORT or IP_MULTICAST_LOOP -#else -#ifdef SO_REUSEPORT - if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT, - (const char*)&reuseFlag, sizeof reuseFlag) < 0) { - socketErr(env, "setsockopt(SO_REUSEPORT) error: "); - closeSocket(newSocket); - return -1; - } -#endif - -#ifdef IP_MULTICAST_LOOP - const u_int8_t loop = (u_int8_t)setLoopback; - if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_LOOP, - (const char*)&loop, sizeof loop) < 0) { - socketErr(env, "setsockopt(IP_MULTICAST_LOOP) error: "); - closeSocket(newSocket); - return -1; - } -#endif -#endif - - // Note: Windoze requires binding, even if the port number is 0 -#if defined(__WIN32__) || defined(_WIN32) -#else - if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) { -#endif - MAKE_SOCKADDR_IN(name, ReceivingSocketAddr, port.num()); - if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) { - char tmpBuffer[100]; - sprintf(tmpBuffer, "bind() error (port number: %d): ", - ntohs(port.num())); - socketErr(env, tmpBuffer); - closeSocket(newSocket); - return -1; - } -#if defined(__WIN32__) || defined(_WIN32) -#else - } -#endif - - // Set the sending interface for multicasts, if it's not the default: - if (SendingInterfaceAddr != INADDR_ANY) { - struct in_addr addr; - addr.s_addr = SendingInterfaceAddr; - - if (setsockopt(newSocket, IPPROTO_IP, IP_MULTICAST_IF, - (const char*)&addr, sizeof addr) < 0) { - socketErr(env, "error setting outgoing multicast interface: "); - closeSocket(newSocket); - return -1; - } - } - - return newSocket; -} - -int setupStreamSocket(UsageEnvironment& env, - Port port, Boolean makeNonBlocking) { - if (!initializeWinsockIfNecessary()) { - socketErr(env, "Failed to initialize 'winsock': "); - return -1; - } - - int newSocket = socket(AF_INET, SOCK_STREAM, 0); - if (newSocket < 0) { - socketErr(env, "unable to create stream socket: "); - return newSocket; - } - - const int reuseFlag = 1; - if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, - (const char*)&reuseFlag, sizeof reuseFlag) < 0) { - socketErr(env, "setsockopt(SO_REUSEADDR) error: "); - closeSocket(newSocket); - return -1; - } - - // SO_REUSEPORT doesn't really make sense for TCP sockets, so we - // normally don't set them. However, if you really want to do this - // #define REUSE_FOR_TCP -#ifdef REUSE_FOR_TCP -#if defined(__WIN32__) || defined(_WIN32) - // Windoze doesn't handle SO_REUSEPORT -#else -#ifdef SO_REUSEPORT - if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT, - (const char*)&reuseFlag, sizeof reuseFlag) < 0) { - socketErr(env, "setsockopt(SO_REUSEPORT) error: "); - closeSocket(newSocket); - return -1; - } -#endif -#endif -#endif - - // Note: Windoze requires binding, even if the port number is 0 -#if defined(__WIN32__) || defined(_WIN32) -#else - if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) { -#endif - MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num()); - if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) { - char tmpBuffer[100]; - sprintf(tmpBuffer, "bind() error (port number: %d): ", - ntohs(port.num())); - socketErr(env, tmpBuffer); - closeSocket(newSocket); - return -1; - } -#if defined(__WIN32__) || defined(_WIN32) -#else - } -#endif - - if (makeNonBlocking) { - // Make the socket non-blocking: -#if defined(__WIN32__) || defined(_WIN32) || defined(IMN_PIM) - unsigned long arg = 1; - if (ioctlsocket(newSocket, FIONBIO, &arg) != 0) { - -#elif defined(VXWORKS) - int arg = 1; - if (ioctl(newSocket, FIONBIO, (int)&arg) != 0) { - -#else - int curFlags = fcntl(newSocket, F_GETFL, 0); - if (fcntl(newSocket, F_SETFL, curFlags|O_NONBLOCK) < 0) { -#endif - socketErr(env, "failed to make non-blocking: "); - closeSocket(newSocket); - return -1; - } - } - - return newSocket; -} - -#ifndef IMN_PIM -static int blockUntilReadable(UsageEnvironment& env, - int socket, struct timeval* timeout) { - int result = -1; - do { - fd_set rd_set; - FD_ZERO(&rd_set); - if (socket < 0) break; - FD_SET((unsigned) socket, &rd_set); - const unsigned numFds = socket+1; - - result = select(numFds, &rd_set, NULL, NULL, timeout); - if (timeout != NULL && result == 0) { - break; // this is OK - timeout occurred - } else if (result <= 0) { -#if defined(__WIN32__) || defined(_WIN32) -#else - if (errno == EINTR || errno == EAGAIN) continue; -#endif - socketErr(env, "select() error: "); - break; - } - - if (!FD_ISSET(socket, &rd_set)) { - socketErr(env, "select() error - !FD_ISSET"); - break; - } - } while (0); - - return result; -} -#else -extern int blockUntilReadable(UsageEnvironment& env, - int socket, struct timeval* timeout); -#endif - -int readSocket(UsageEnvironment& env, - int socket, unsigned char* buffer, unsigned bufferSize, - struct sockaddr_in& fromAddress, - struct timeval* timeout) { - int bytesRead = -1; - do { - int result = blockUntilReadable(env, socket, timeout); - if (timeout != NULL && result == 0) { - bytesRead = 0; - break; - } else if (result <= 0) { - break; - } - - SOCKLEN_T addressSize = sizeof fromAddress; - bytesRead = recvfrom(socket, (char*)buffer, bufferSize, 0, - (struct sockaddr*)&fromAddress, - &addressSize); - if (bytesRead < 0) { - //##### HACK to work around bugs in Linux and Windows: - int err = env.getErrno(); - if (err == 111 /*ECONNREFUSED (Linux)*/ -#if defined(__WIN32__) || defined(_WIN32) - // What a piece of crap Windows is. Sometimes - // recvfrom() returns -1, but with an 'errno' of 0. - // This appears not to be a real error; just treat - // it as if it were a read of zero bytes, and hope - // we don't have to do anything else to 'reset' - // this alleged error: - || err == 0 -#else - || err == EAGAIN -#endif - || err == 113 /*EHOSTUNREACH (Linux)*/) { - //Why does Linux return this for datagram sock? - fromAddress.sin_addr.s_addr = 0; - return 0; - } - //##### END HACK - socketErr(env, "recvfrom() error: "); - break; - } - } while (0); - - return bytesRead; -} - - -int readSocketExact(UsageEnvironment& env, - int socket, unsigned char* buffer, unsigned bufferSize, - struct sockaddr_in& fromAddress, - struct timeval* timeout) { - /* read EXACTLY bufferSize bytes from the socket into the buffer. - fromaddress is address of last read. - return the number of bytes acually read when an error occurs - */ - int bsize = bufferSize; - int bytesRead = 0; - int totBytesRead =0; - do { - bytesRead = readSocket (env, socket, buffer + totBytesRead, bsize, - fromAddress, timeout); - if (bytesRead <= 0) break; - totBytesRead += bytesRead; - bsize -= bytesRead; - } while (bsize != 0); - - return totBytesRead; -} - -Boolean writeSocket(UsageEnvironment& env, - int socket, struct in_addr address, Port port, - u_int8_t ttlArg, - unsigned char* buffer, unsigned bufferSize) { - do { - if (ttlArg != 0) { - // Before sending, set the socket's TTL: -#if defined(__WIN32__) || defined(_WIN32) -#define TTL_TYPE int -#else -#define TTL_TYPE u_int8_t -#endif - TTL_TYPE ttl = (TTL_TYPE)ttlArg; - if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, - (const char*)&ttl, sizeof ttl) < 0) { - socketErr(env, "setsockopt(IP_MULTICAST_TTL) error: "); - break; - } - } - - MAKE_SOCKADDR_IN(dest, address.s_addr, port.num()); - int bytesSent = sendto(socket, (char*)buffer, bufferSize, 0, - (struct sockaddr*)&dest, sizeof dest); - if (bytesSent != (int)bufferSize) { - char tmpBuf[100]; - sprintf(tmpBuf, "writeSocket(%d), sendTo() error: wrote %d bytes instead of %u: ", socket, bytesSent, bufferSize); - socketErr(env, tmpBuf); - break; - } - - return True; - } while (0); - - return False; -} - -static unsigned getBufferSize(UsageEnvironment& env, int bufOptName, - int socket) { - unsigned curSize; - SOCKLEN_T sizeSize = sizeof curSize; - if (getsockopt(socket, SOL_SOCKET, bufOptName, - (char*)&curSize, &sizeSize) < 0) { - socketErr(env, "getBufferSize() error: "); - return 0; - } - - return curSize; -} -unsigned getSendBufferSize(UsageEnvironment& env, int socket) { - return getBufferSize(env, SO_SNDBUF, socket); -} -unsigned getReceiveBufferSize(UsageEnvironment& env, int socket) { - return getBufferSize(env, SO_RCVBUF, socket); -} - -static unsigned setBufferTo(UsageEnvironment& env, int bufOptName, - int socket, unsigned requestedSize) { - SOCKLEN_T sizeSize = sizeof requestedSize; - setsockopt(socket, SOL_SOCKET, bufOptName, (char*)&requestedSize, sizeSize); - - // Get and return the actual, resulting buffer size: - return getBufferSize(env, bufOptName, socket); -} -unsigned setSendBufferTo(UsageEnvironment& env, - int socket, unsigned requestedSize) { - return setBufferTo(env, SO_SNDBUF, socket, requestedSize); -} -unsigned setReceiveBufferTo(UsageEnvironment& env, - int socket, unsigned requestedSize) { - return setBufferTo(env, SO_RCVBUF, socket, requestedSize); -} - -static unsigned increaseBufferTo(UsageEnvironment& env, int bufOptName, - int socket, unsigned requestedSize) { - // First, get the current buffer size. If it's already at least - // as big as what we're requesting, do nothing. - unsigned curSize = getBufferSize(env, bufOptName, socket); - - // Next, try to increase the buffer to the requested size, - // or to some smaller size, if that's not possible: - while (requestedSize > curSize) { - SOCKLEN_T sizeSize = sizeof requestedSize; - if (setsockopt(socket, SOL_SOCKET, bufOptName, - (char*)&requestedSize, sizeSize) >= 0) { - // success - return requestedSize; - } - requestedSize = (requestedSize+curSize)/2; - } - - return getBufferSize(env, bufOptName, socket); -} -unsigned increaseSendBufferTo(UsageEnvironment& env, - int socket, unsigned requestedSize) { - return increaseBufferTo(env, SO_SNDBUF, socket, requestedSize); -} -unsigned increaseReceiveBufferTo(UsageEnvironment& env, - int socket, unsigned requestedSize) { - return increaseBufferTo(env, SO_RCVBUF, socket, requestedSize); -} - -Boolean socketJoinGroup(UsageEnvironment& env, int socket, - netAddressBits groupAddress){ - if (!IsMulticastAddress(groupAddress)) return True; // ignore this case - - struct ip_mreq imr; - imr.imr_multiaddr.s_addr = groupAddress; - imr.imr_interface.s_addr = ReceivingInterfaceAddr; - if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (const char*)&imr, sizeof (struct ip_mreq)) < 0) { -#if defined(__WIN32__) || defined(_WIN32) - if (env.getErrno() != 0) { - // That piece-of-shit toy operating system (Windows) sometimes lies - // about setsockopt() failing! -#endif - socketErr(env, "setsockopt(IP_ADD_MEMBERSHIP) error: "); - return False; -#if defined(__WIN32__) || defined(_WIN32) - } -#endif - } - - return True; -} - -Boolean socketLeaveGroup(UsageEnvironment&, int socket, - netAddressBits groupAddress) { - if (!IsMulticastAddress(groupAddress)) return True; // ignore this case - - struct ip_mreq imr; - imr.imr_multiaddr.s_addr = groupAddress; - imr.imr_interface.s_addr = ReceivingInterfaceAddr; - if (setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, - (const char*)&imr, sizeof (struct ip_mreq)) < 0) { - return False; - } - - return True; -} - -// The source-specific join/leave operations require special setsockopt() -// commands, and a special structure (ip_mreq_source). If the include files -// didn't define these, we do so here: -#ifndef IP_ADD_SOURCE_MEMBERSHIP -#ifdef LINUX -#define IP_ADD_SOURCE_MEMBERSHIP 39 -#define IP_DROP_SOURCE_MEMBERSHIP 40 -#else -#define IP_ADD_SOURCE_MEMBERSHIP 67 -#define IP_DROP_SOURCE_MEMBERSHIP 68 -#endif - -struct ip_mreq_source { - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_sourceaddr; /* IP address of source */ - struct in_addr imr_interface; /* local IP address of interface */ -}; -#endif - -Boolean socketJoinGroupSSM(UsageEnvironment& env, int socket, - netAddressBits groupAddress, - netAddressBits sourceFilterAddr) { - if (!IsMulticastAddress(groupAddress)) return True; // ignore this case - - struct ip_mreq_source imr; - imr.imr_multiaddr.s_addr = groupAddress; - imr.imr_sourceaddr.s_addr = sourceFilterAddr; - imr.imr_interface.s_addr = ReceivingInterfaceAddr; - if (setsockopt(socket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, - (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) { - socketErr(env, "setsockopt(IP_ADD_SOURCE_MEMBERSHIP) error: "); - return False; - } - - return True; -} - -Boolean socketLeaveGroupSSM(UsageEnvironment& /*env*/, int socket, - netAddressBits groupAddress, - netAddressBits sourceFilterAddr) { - if (!IsMulticastAddress(groupAddress)) return True; // ignore this case - - struct ip_mreq_source imr; - imr.imr_multiaddr.s_addr = groupAddress; - imr.imr_sourceaddr.s_addr = sourceFilterAddr; - imr.imr_interface.s_addr = ReceivingInterfaceAddr; - if (setsockopt(socket, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, - (const char*)&imr, sizeof (struct ip_mreq_source)) < 0) { - return False; - } - - return True; -} - -static Boolean getSourcePort0(int socket, portNumBits& resultPortNum/*host order*/) { - sockaddr_in test; test.sin_port = 0; - SOCKLEN_T len = sizeof test; - if (getsockname(socket, (struct sockaddr*)&test, &len) < 0) return False; - - resultPortNum = ntohs(test.sin_port); - return True; -} - -Boolean getSourcePort(UsageEnvironment& env, int socket, Port& port) { - portNumBits portNum = 0; - if (!getSourcePort0(socket, portNum) || portNum == 0) { - // Hack - call bind(), then try again: - MAKE_SOCKADDR_IN(name, INADDR_ANY, 0); - bind(socket, (struct sockaddr*)&name, sizeof name); - - if (!getSourcePort0(socket, portNum) || portNum == 0) { - socketErr(env, "getsockname() error: "); - return False; - } - } - - port = Port(portNum); - return True; -} - -static Boolean badAddress(netAddressBits addr) { - // Check for some possible erroneous addresses: - netAddressBits hAddr = ntohl(addr); - return (hAddr == 0x7F000001 /* 127.0.0.1 */ - || hAddr == 0 - || hAddr == (netAddressBits)(~0)); -} - -Boolean loopbackWorks = 1; - -netAddressBits ourSourceAddressForMulticast(UsageEnvironment& env) { - static netAddressBits ourAddress = 0; - int sock = -1; - struct in_addr testAddr; - - if (ourAddress == 0) { - // We need to find our source address - struct sockaddr_in fromAddr; - fromAddr.sin_addr.s_addr = 0; - - // Get our address by sending a (0-TTL) multicast packet, - // receiving it, and looking at the source address used. - // (This is kinda bogus, but it provides the best guarantee - // that other nodes will think our address is the same as we do.) - do { - loopbackWorks = 0; // until we learn otherwise - - testAddr.s_addr = our_inet_addr("228.67.43.91"); // arbitrary - Port testPort(15947); // ditto - - ReceivingSocketAddr = INADDR_ANY; - - sock = setupDatagramSocket(env, testPort); - if (sock < 0) break; - - if (!socketJoinGroup(env, sock, testAddr.s_addr)) break; - - unsigned char testString[] = "hostIdTest"; - unsigned testStringLength = sizeof testString; - - if (!writeSocket(env, sock, testAddr, testPort, 0, - testString, testStringLength)) break; - - unsigned char readBuffer[20]; - struct timeval timeout; - timeout.tv_sec = 5; - timeout.tv_usec = 0; - int bytesRead = readSocket(env, sock, - readBuffer, sizeof readBuffer, - fromAddr, &timeout); - if (bytesRead == 0 // timeout occurred - || bytesRead != (int)testStringLength - || strncmp((char*)readBuffer, (char*)testString, - testStringLength) != 0) { - break; - } - - loopbackWorks = 1; - } while (0); - - if (!loopbackWorks) do { - // We couldn't find our address using multicast loopback - // so try instead to look it up directly. - char hostname[100]; - hostname[0] = '\0'; -#ifndef CRIS - gethostname(hostname, sizeof hostname); -#endif - if (hostname[0] == '\0') { - env.setResultErrMsg("initial gethostname() failed"); - break; - } - -#if defined(VXWORKS) -#include - if (ERROR == (ourAddress = hostGetByName( hostname ))) break; -#else - struct hostent* hstent - = (struct hostent*)gethostbyname(hostname); - if (hstent == NULL || hstent->h_length != 4) { - env.setResultErrMsg("initial gethostbyname() failed"); - break; - } - // Take the first address that's not bad - // (This code, like many others, won't handle IPv6) - netAddressBits addr = 0; - for (unsigned i = 0; ; ++i) { - char* addrPtr = hstent->h_addr_list[i]; - if (addrPtr == NULL) break; - - netAddressBits a = *(netAddressBits*)addrPtr; - if (!badAddress(a)) { - addr = a; - break; - } - } - if (addr != 0) { - fromAddr.sin_addr.s_addr = addr; - } else { - env.setResultMsg("no address"); - break; - } - } while (0); - - // Make sure we have a good address: - netAddressBits from = fromAddr.sin_addr.s_addr; - if (badAddress(from)) { - char tmp[100]; - sprintf(tmp, - "This computer has an invalid IP address: 0x%x", - (netAddressBits)(ntohl(from))); - env.setResultMsg(tmp); - from = 0; - } - - ourAddress = from; -#endif - - if (sock >= 0) { - socketLeaveGroup(env, sock, testAddr.s_addr); - closeSocket(sock); - } - - // Use our newly-discovered IP address, and the current time, - // to initialize the random number generator's seed: - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - unsigned seed = ourAddress^timeNow.tv_sec^timeNow.tv_usec; - our_srandom(seed); - } - return ourAddress; -} - -netAddressBits chooseRandomIPv4SSMAddress(UsageEnvironment& env) { - // First, a hack to ensure that our random number generator is seeded: - (void) ourSourceAddressForMulticast(env); - - // Choose a random address in the range [232.0.1.0, 232.255.255.255) - // i.e., [0xE8000100, 0xE8FFFFFF) - netAddressBits const first = 0xE8000100, lastPlus1 = 0xE8FFFFFF; - netAddressBits const range = lastPlus1 - first; - - return htonl(first + ((netAddressBits)our_random())%range); -} - -char const* timestampString() { - struct timeval tvNow; - gettimeofday(&tvNow, NULL); - -#if !defined(_WIN32_WCE) - static char timeString[9]; // holds hh:mm:ss plus trailing '\0' - char const* ctimeResult = ctime((time_t*)&tvNow.tv_sec); - char const* from = &ctimeResult[11]; - int i; - for (i = 0; i < 8; ++i) { - timeString[i] = from[i]; - } - timeString[i] = '\0'; -#else - // WinCE apparently doesn't have "ctime()", so instead, construct - // a timestamp string just using the integer and fractional parts - // of "tvNow": - static char timeString[50]; - sprintf(timeString, "%lu.%06ld", tvNow.tv_sec, tvNow.tv_usec); -#endif - - return (char const*)&timeString; -} - -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(IMN_PIM) -// For Windoze, we need to implement our own gettimeofday() -#if !defined(_WIN32_WCE) -#include -#endif - -int gettimeofday(struct timeval* tp, int* /*tz*/) { -#if defined(_WIN32_WCE) - /* FILETIME of Jan 1 1970 00:00:00. */ - static const unsigned __int64 epoch = 116444736000000000L; - - FILETIME file_time; - SYSTEMTIME system_time; - ULARGE_INTEGER ularge; - - GetSystemTime(&system_time); - SystemTimeToFileTime(&system_time, &file_time); - ularge.LowPart = file_time.dwLowDateTime; - ularge.HighPart = file_time.dwHighDateTime; - - tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L); - tp->tv_usec = (long) (system_time.wMilliseconds * 1000); -#else - struct timeb tb; - ftime(&tb); - tp->tv_sec = tb.time; - tp->tv_usec = 1000*tb.millitm; -#endif - return 0; -} -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/IOHandlers.cpp b/mythtv/libs/libmythlivemedia/groupsock/IOHandlers.cpp deleted file mode 100644 index 383ff8a28bb..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/IOHandlers.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-1998 Live Networks, Inc. All rights reserved. -// IO event handlers -// Implementation - -#include "IOHandlers.hh" -#include "TunnelEncaps.hh" - -//##### TEMP: Use a single buffer, sized for UDP tunnels: -//##### This assumes that the I/O handlers are non-reentrant -static unsigned const maxPacketLength = 50*1024; // bytes - // This is usually overkill, because UDP packets are usually no larger - // than the typical Ethernet MTU (1500 bytes). However, I've seen - // reports of Windows Media Servers sending UDP packets as large as - // 27 kBytes. These will probably undego lots of IP-level - // fragmentation, but that occurs below us. We just have to hope that - // fragments don't get lost. -static unsigned const ioBufferSize - = maxPacketLength + TunnelEncapsulationTrailerMaxSize; -static unsigned char ioBuffer[ioBufferSize]; - - -void socketReadHandler(Socket* sock, int /*mask*/) { - unsigned bytesRead; - struct sockaddr_in fromAddress; - UsageEnvironment& saveEnv = sock->env(); - // because handleRead(), if it fails, may delete "sock" - if (!sock->handleRead(ioBuffer, ioBufferSize, bytesRead, fromAddress)) { - saveEnv.reportBackgroundError(); - } -} diff --git a/mythtv/libs/libmythlivemedia/groupsock/NetAddress.cpp b/mythtv/libs/libmythlivemedia/groupsock/NetAddress.cpp deleted file mode 100644 index 42cafd30e86..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/NetAddress.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-1998 Live Networks, Inc. All rights reserved. -// Network Addresses -// Implementation - -#include "NetAddress.hh" -#include "GroupsockHelper.hh" - -#include -#if defined(__WIN32__) || defined(_WIN32) -#else -#ifndef INADDR_NONE -#define INADDR_NONE 0xFFFFFFFF -#endif -#endif - -////////// NetAddress ////////// - -NetAddress::NetAddress(u_int8_t const* data, unsigned length) { - assign(data, length); -} - -NetAddress::NetAddress(unsigned length) { - fData = new u_int8_t[length]; - if (fData == NULL) { - fLength = 0; - return; - } - - for (unsigned i = 0; i < length; ++i) fData[i] = 0; - fLength = length; -} - -NetAddress::NetAddress(NetAddress const& orig) { - assign(orig.data(), orig.length()); -} - -NetAddress& NetAddress::operator=(NetAddress const& rightSide) { - if (&rightSide != this) { - clean(); - assign(rightSide.data(), rightSide.length()); - } - return *this; -} - -NetAddress::~NetAddress() { - clean(); -} - -void NetAddress::assign(u_int8_t const* data, unsigned length) { - fData = new u_int8_t[length]; - if (fData == NULL) { - fLength = 0; - return; - } - - for (unsigned i = 0; i < length; ++i) fData[i] = data[i]; - fLength = length; -} - -void NetAddress::clean() { - delete[] fData; fData = NULL; - fLength = 0; -} - - -////////// NetAddressList ////////// - -NetAddressList::NetAddressList(char const* hostname) - : fNumAddresses(0), fAddressArray(NULL) { - struct hostent* host; - - // Check first whether "hostname" is an IP address string: - netAddressBits addr = our_inet_addr((char*)hostname); - if (addr != INADDR_NONE) { // yes it was an IP address string - //##### host = gethostbyaddr((char*)&addr, sizeof (netAddressBits), AF_INET); - host = NULL; // don't bother calling gethostbyaddr(); we only want 1 addr - - if (host == NULL) { - // For some unknown reason, gethostbyaddr() failed, so just - // return a 1-element list with the address we were given: - fNumAddresses = 1; - fAddressArray = new NetAddress*[fNumAddresses]; - if (fAddressArray == NULL) return; - - fAddressArray[0] = new NetAddress((u_int8_t*)&addr, - sizeof (netAddressBits)); - return; - } - } else { // Try resolving "hostname" as a real host name - -#if defined(VXWORKS) - char hostentBuf[512]; - host = (struct hostent*)resolvGetHostByName((char*)hostname,(char*)&hostentBuf,sizeof hostentBuf); -#else - host = our_gethostbyname((char*)hostname); -#endif - - if (host == NULL) { - // It was a host name, and we couldn't resolve it. We're SOL. - return; - } - } - - u_int8_t const** const hAddrPtr - = (u_int8_t const**)host->h_addr_list; - if (hAddrPtr != NULL) { - // First, count the number of addresses: - u_int8_t const** hAddrPtr1 = hAddrPtr; - while (*hAddrPtr1 != NULL) { - ++fNumAddresses; - ++hAddrPtr1; - } - - // Next, set up the list: - fAddressArray = new NetAddress*[fNumAddresses]; - if (fAddressArray == NULL) return; - - for (unsigned i = 0; i < fNumAddresses; ++i) { - fAddressArray[i] - = new NetAddress(hAddrPtr[i], host->h_length); - } - } -} - -NetAddressList::NetAddressList(NetAddressList const& orig) { - assign(orig.numAddresses(), orig.fAddressArray); -} - -NetAddressList& NetAddressList::operator=(NetAddressList const& rightSide) { - if (&rightSide != this) { - clean(); - assign(rightSide.numAddresses(), rightSide.fAddressArray); - } - return *this; -} - -NetAddressList::~NetAddressList() { - clean(); -} - -void NetAddressList::assign(unsigned numAddresses, NetAddress** addressArray) { - fAddressArray = new NetAddress*[numAddresses]; - if (fAddressArray == NULL) { - fNumAddresses = 0; - return; - } - - for (unsigned i = 0; i < numAddresses; ++i) { - fAddressArray[i] = new NetAddress(*addressArray[i]); - } - fNumAddresses = numAddresses; -} - -void NetAddressList::clean() { - while (fNumAddresses-- > 0) { - delete fAddressArray[fNumAddresses]; - } - delete[] fAddressArray; fAddressArray = NULL; -} - -NetAddress const* NetAddressList::firstAddress() const { - if (fNumAddresses == 0) return NULL; - - return fAddressArray[0]; -} - -////////// NetAddressList::Iterator ////////// -NetAddressList::Iterator::Iterator(NetAddressList const& addressList) - : fAddressList(addressList), fNextIndex(0) {} - -NetAddress const* NetAddressList::Iterator::nextAddress() { - if (fNextIndex >= fAddressList.numAddresses()) return NULL; // no more - return fAddressList.fAddressArray[fNextIndex++]; -} - - -////////// Port ////////// - -Port::Port(portNumBits num /* in host byte order */) { - fPortNum = htons(num); -} - -UsageEnvironment& operator<<(UsageEnvironment& s, const Port& p) { - return s << ntohs(p.num()); -} - - -////////// AddressPortLookupTable ////////// - -AddressPortLookupTable::AddressPortLookupTable() - : fTable(HashTable::create(3)) { // three-word keys are used -} - -AddressPortLookupTable::~AddressPortLookupTable() { - delete fTable; -} - -void* AddressPortLookupTable::Add(netAddressBits address1, - netAddressBits address2, - Port port, void* value) { - int key[3]; - key[0] = (int)address1; - key[1] = (int)address2; - key[2] = (int)port.num(); - return fTable->Add((char*)key, value); -} - -void* AddressPortLookupTable::Lookup(netAddressBits address1, - netAddressBits address2, - Port port) { - int key[3]; - key[0] = (int)address1; - key[1] = (int)address2; - key[2] = (int)port.num(); - return fTable->Lookup((char*)key); -} - -Boolean AddressPortLookupTable::Remove(netAddressBits address1, - netAddressBits address2, - Port port) { - int key[3]; - key[0] = (int)address1; - key[1] = (int)address2; - key[2] = (int)port.num(); - return fTable->Remove((char*)key); -} - -AddressPortLookupTable::Iterator::Iterator(AddressPortLookupTable& table) - : fIter(HashTable::Iterator::create(*(table.fTable))) { -} - -AddressPortLookupTable::Iterator::~Iterator() { - delete fIter; -} - -void* AddressPortLookupTable::Iterator::next() { - char const* key; // dummy - return fIter->next(key); -} - -////////// Misc. ////////// - -Boolean IsMulticastAddress(netAddressBits address) { - // Note: We return False for addresses in the range 224.0.0.0 - // through 224.0.0.255, because these are non-routable - // Note: IPv4-specific ##### - netAddressBits addressInHostOrder = ntohl(address); - return addressInHostOrder > 0xE00000FF && - addressInHostOrder <= 0xEFFFFFFF; -} diff --git a/mythtv/libs/libmythlivemedia/groupsock/NetInterface.cpp b/mythtv/libs/libmythlivemedia/groupsock/NetInterface.cpp deleted file mode 100644 index 42da045d5f2..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/NetInterface.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-1998 Live Networks, Inc. All rights reserved. -// Network Interfaces -// Implementation - -#include "NetInterface.hh" -#include "GroupsockHelper.hh" - -#ifndef NO_STRSTREAM -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(__MINGW32__) -#include -#else -#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) -#include -#else -#include -#endif -#endif -#endif - -////////// NetInterface ////////// - -UsageEnvironment* NetInterface::DefaultUsageEnvironment = NULL; - -NetInterface::NetInterface() { -} - -NetInterface::~NetInterface() { -} - - -////////// NetInterface ////////// - -DirectedNetInterface::DirectedNetInterface() { -} - -DirectedNetInterface::~DirectedNetInterface() { -} - - -////////// DirectedNetInterfaceSet ////////// - -DirectedNetInterfaceSet::DirectedNetInterfaceSet() - : fTable(HashTable::create(ONE_WORD_HASH_KEYS)) { -} - -DirectedNetInterfaceSet::~DirectedNetInterfaceSet() { - delete fTable; -} - -DirectedNetInterface* -DirectedNetInterfaceSet::Add(DirectedNetInterface const* interf) { - return (DirectedNetInterface*) fTable->Add((char*)interf, (void*)interf); -} - -Boolean -DirectedNetInterfaceSet::Remove(DirectedNetInterface const* interf) { - return fTable->Remove((char*)interf); -} - -DirectedNetInterfaceSet::Iterator:: -Iterator(DirectedNetInterfaceSet& interfaces) - : fIter(HashTable::Iterator::create(*(interfaces.fTable))) { -} - -DirectedNetInterfaceSet::Iterator::~Iterator() { - delete fIter; -} - -DirectedNetInterface* DirectedNetInterfaceSet::Iterator::next() { - char const* key; // dummy - return (DirectedNetInterface*) fIter->next(key); -}; - - -////////// Socket ////////// - -int Socket::DebugLevel = 1; // default value - -Socket::Socket(UsageEnvironment& env, Port port, Boolean setLoopback) - : fEnv(DefaultUsageEnvironment != NULL ? *DefaultUsageEnvironment : env), fPort(port), fSetLoopback(setLoopback) { - fSocketNum = setupDatagramSocket(fEnv, port, setLoopback); -} - -Socket::~Socket() { - closeSocket(fSocketNum); -} - -Boolean Socket::changePort(Port newPort) { - closeSocket(fSocketNum); - fSocketNum = setupDatagramSocket(fEnv, newPort, fSetLoopback); - return fSocketNum >= 0; -} - -UsageEnvironment& operator<<(UsageEnvironment& s, const Socket& sock) { - return s << timestampString() << " Socket(" << sock.socketNum() << ")"; -} - -////////// SocketLookupTable ////////// - -SocketLookupTable::SocketLookupTable() - : fTable(HashTable::create(ONE_WORD_HASH_KEYS)) { -} - -SocketLookupTable::~SocketLookupTable() { - delete fTable; -} - -Socket* SocketLookupTable::Fetch(UsageEnvironment& env, Port port, - Boolean& isNew) { - isNew = False; - Socket* sock; - do { - sock = (Socket*) fTable->Lookup((char*)(long)(port.num())); - if (sock == NULL) { // we need to create one: - sock = CreateNew(env, port); - if (sock == NULL || sock->socketNum() < 0) break; - - fTable->Add((char*)(long)(port.num()), (void*)sock); - isNew = True; - } - - return sock; - } while (0); - - delete sock; - return NULL; -} - -Boolean SocketLookupTable::Remove(Socket const* sock) { - return fTable->Remove( (char*)(long)(sock->port().num()) ); -} - -////////// NetInterfaceTrafficStats ////////// - -NetInterfaceTrafficStats::NetInterfaceTrafficStats() { - fTotNumPackets = fTotNumBytes = 0.0; -} - -void NetInterfaceTrafficStats::countPacket(unsigned packetSize) { - fTotNumPackets += 1.0; - fTotNumBytes += packetSize; -} - -Boolean NetInterfaceTrafficStats::haveSeenTraffic() const { - return fTotNumPackets != 0.0; -} diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/GroupEId.hh b/mythtv/libs/libmythlivemedia/groupsock/include/GroupEId.hh deleted file mode 100644 index ccc2cb0286a..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/GroupEId.hh +++ /dev/null @@ -1,98 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "multikit" Multicast Application Shell -// Copyright (c) 1996-1997, Live Networks, Inc. All rights reserved -// "Group Endpoint Id" -// C++ header - -#ifndef _GROUPEID_HH -#define _GROUPEID_HH - -#ifndef _BOOLEAN_HH -#include "Boolean.hh" -#endif - -#ifndef _NET_ADDRESS_HH -#include "NetAddress.hh" -#endif - -const u_int8_t MAX_TTL = 255; - -class Scope { - public: - Scope(u_int8_t ttl = 0, const char* publicKey = NULL); - Scope(const Scope& orig); - Scope& operator=(const Scope& rightSide); - ~Scope(); - - u_int8_t ttl() const - { return fTTL; } - - const char* publicKey() const - { return fPublicKey; } - unsigned publicKeySize() const; - - private: - void assign(u_int8_t ttl, const char* publicKey); - void clean(); - - u_int8_t fTTL; - char* fPublicKey; -}; - -class GroupEId { -public: - GroupEId(struct in_addr const& groupAddr, - portNumBits portNum, Scope const& scope, - unsigned numSuccessiveGroupAddrs = 1); - // used for a 'source-independent multicast' group - GroupEId(struct in_addr const& groupAddr, - struct in_addr const& sourceFilterAddr, - portNumBits portNum, - unsigned numSuccessiveGroupAddrs = 1); - // used for a 'source-specific multicast' group - GroupEId(); // used only as a temp constructor prior to initialization - - struct in_addr const& groupAddress() const { return fGroupAddress; } - struct in_addr const& sourceFilterAddress() const { return fSourceFilterAddress; } - - Boolean isSSM() const; - - unsigned numSuccessiveGroupAddrs() const { - // could be >1 for hier encoding - return fNumSuccessiveGroupAddrs; - } - - portNumBits portNum() const { return fPortNum; } - - const Scope& scope() const { return fScope; } - -private: - void init(struct in_addr const& groupAddr, - struct in_addr const& sourceFilterAddr, - portNumBits portNum, - Scope const& scope, - unsigned numSuccessiveGroupAddrs); - -private: - struct in_addr fGroupAddress; - struct in_addr fSourceFilterAddress; - unsigned fNumSuccessiveGroupAddrs; - portNumBits fPortNum; - Scope fScope; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/Groupsock.hh b/mythtv/libs/libmythlivemedia/groupsock/include/Groupsock.hh deleted file mode 100644 index 1cb3706d6a2..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/Groupsock.hh +++ /dev/null @@ -1,205 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-1998 Live Networks, Inc. All rights reserved. -// 'Group sockets' -// C++ header - -#ifndef _GROUPSOCK_HH -#define _GROUPSOCK_HH - -#ifndef _GROUPSOCK_VERSION_HH -#include "groupsock_version.hh" -#endif - -#ifndef _NET_INTERFACE_HH -#include "NetInterface.hh" -#endif - -#ifndef _GROUPEID_HH -#include "GroupEId.hh" -#endif - -// An "OutputSocket" is (by default) used only to send packets. -// No packets are received on it (unless a subclass arranges this) - -class OutputSocket: public Socket { -public: - OutputSocket(UsageEnvironment& env); - virtual ~OutputSocket(); - - Boolean write(netAddressBits address, Port port, u_int8_t ttl, - unsigned char* buffer, unsigned bufferSize); - -protected: - OutputSocket(UsageEnvironment& env, Port port); - - portNumBits sourcePortNum() const {return fSourcePort.num();} - -private: // redefined virtual function - virtual Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize, - unsigned& bytesRead, - struct sockaddr_in& fromAddress); - -private: - Port fSourcePort; - u_int8_t fLastSentTTL; -}; - -class destRecord { -public: - destRecord(struct in_addr const& addr, Port const& port, u_int8_t ttl, - destRecord* next); - virtual ~destRecord(); - -public: - destRecord* fNext; - GroupEId fGroupEId; - Port fPort; -}; - -// A "Groupsock" is used to both send and receive packets. -// As the name suggests, it was originally designed to send/receive -// multicast, but it can send/receive unicast as well. - -class Groupsock: public OutputSocket { -public: - Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr, - Port port, u_int8_t ttl); - // used for a 'source-independent multicast' group - Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr, - struct in_addr const& sourceFilterAddr, - Port port); - // used for a 'source-specific multicast' group - virtual ~Groupsock(); - - void changeDestinationParameters(struct in_addr const& newDestAddr, - Port newDestPort, int newDestTTL); - // By default, the destination address, port and ttl for - // outgoing packets are those that were specified in - // the constructor. This works OK for multicast sockets, - // but for unicast we usually want the destination port - // number, at least, to be different from the source port. - // (If a parameter is 0 (or ~0 for ttl), then no change made.) - - // As a special case, we also allow multiple destinations (addresses & ports) - // (This can be used to implement multi-unicast.) - void addDestination(struct in_addr const& addr, Port const& port); - void removeDestination(struct in_addr const& addr, Port const& port); - void removeAllDestinations(); - - struct in_addr const& groupAddress() const { - return fIncomingGroupEId.groupAddress(); - } - struct in_addr const& sourceFilterAddress() const { - return fIncomingGroupEId.sourceFilterAddress(); - } - - Boolean isSSM() const { - return fIncomingGroupEId.isSSM(); - } - - u_int8_t ttl() const { return fTTL; } - - void multicastSendOnly(); // send, but don't receive any multicast packets - - Boolean output(UsageEnvironment& env, u_int8_t ttl, - unsigned char* buffer, unsigned bufferSize, - DirectedNetInterface* interfaceNotToFwdBackTo = NULL); - - DirectedNetInterfaceSet& members() { return fMembers; } - - Boolean deleteIfNoMembers; - Boolean isSlave; // for tunneling - - static NetInterfaceTrafficStats statsIncoming; - static NetInterfaceTrafficStats statsOutgoing; - static NetInterfaceTrafficStats statsRelayedIncoming; - static NetInterfaceTrafficStats statsRelayedOutgoing; - NetInterfaceTrafficStats statsGroupIncoming; // *not* static - NetInterfaceTrafficStats statsGroupOutgoing; // *not* static - NetInterfaceTrafficStats statsGroupRelayedIncoming; // *not* static - NetInterfaceTrafficStats statsGroupRelayedOutgoing; // *not* static - - Boolean wasLoopedBackFromUs(UsageEnvironment& env, - struct sockaddr_in& fromAddress); - - static Groupsock* lookupByName(UsageEnvironment& env, char const* name); - -public: // redefined virtual functions - virtual Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize, - unsigned& bytesRead, - struct sockaddr_in& fromAddress); - -private: - int outputToAllMembersExcept(DirectedNetInterface* exceptInterface, - u_int8_t ttlToFwd, - unsigned char* data, unsigned size, - netAddressBits sourceAddr); - -private: - GroupEId fIncomingGroupEId; - destRecord* fDests; - u_int8_t fTTL; - DirectedNetInterfaceSet fMembers; -}; - -UsageEnvironment& operator<<(UsageEnvironment& s, const Groupsock& g); - -// A data structure for looking up a 'groupsock' -// by (multicast address, port), or by socket number -class GroupsockLookupTable { -public: - Groupsock* Fetch(UsageEnvironment& env, netAddressBits groupAddress, - Port port, u_int8_t ttl, Boolean& isNew); - // Creates a new Groupsock if none already exists - Groupsock* Fetch(UsageEnvironment& env, netAddressBits groupAddress, - netAddressBits sourceFilterAddr, - Port port, Boolean& isNew); - // Creates a new Groupsock if none already exists - Groupsock* Lookup(netAddressBits groupAddress, Port port); - // Returns NULL if none already exists - Groupsock* Lookup(netAddressBits groupAddress, - netAddressBits sourceFilterAddr, - Port port); - // Returns NULL if none already exists - Groupsock* Lookup(UsageEnvironment& env, int sock); - // Returns NULL if none already exists - Boolean Remove(Groupsock const* groupsock); - - // Used to iterate through the groupsocks in the table - class Iterator { - public: - Iterator(GroupsockLookupTable& groupsocks); - - Groupsock* next(); // NULL iff none - - private: - AddressPortLookupTable::Iterator fIter; - }; - -private: - Groupsock* AddNew(UsageEnvironment& env, - netAddressBits groupAddress, - netAddressBits sourceFilterAddress, - Port port, u_int8_t ttl); - -private: - friend class Iterator; - AddressPortLookupTable fTable; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/GroupsockHelper.hh b/mythtv/libs/libmythlivemedia/groupsock/include/GroupsockHelper.hh deleted file mode 100644 index a7a3598dbf8..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/GroupsockHelper.hh +++ /dev/null @@ -1,118 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-2001 Live Networks, Inc. All rights reserved. -// Helper routines to implement 'group sockets' -// C++ header - -#ifndef _GROUPSOCK_HELPER_HH -#define _GROUPSOCK_HELPER_HH - -#ifndef _NET_ADDRESS_HH -#include "NetAddress.hh" -#endif - -int setupDatagramSocket(UsageEnvironment& env, - Port port, Boolean setLoopback = True); -int setupStreamSocket(UsageEnvironment& env, - Port port, Boolean makeNonBlocking = True); - -int readSocket(UsageEnvironment& env, - int socket, unsigned char* buffer, unsigned bufferSize, - struct sockaddr_in& fromAddress, - struct timeval* timeout = NULL); - -int readSocketExact(UsageEnvironment& env, - int socket, unsigned char* buffer, unsigned bufferSize, - struct sockaddr_in& fromAddress, - struct timeval* timeout = NULL); - // like "readSocket()", except that it rereads as many times as needed until - // *exactly* "bufferSize" bytes are read. - -Boolean writeSocket(UsageEnvironment& env, - int socket, struct in_addr address, Port port, - u_int8_t ttlArg, - unsigned char* buffer, unsigned bufferSize); - -unsigned getSendBufferSize(UsageEnvironment& env, int socket); -unsigned getReceiveBufferSize(UsageEnvironment& env, int socket); -unsigned setSendBufferTo(UsageEnvironment& env, - int socket, unsigned requestedSize); -unsigned setReceiveBufferTo(UsageEnvironment& env, - int socket, unsigned requestedSize); -unsigned increaseSendBufferTo(UsageEnvironment& env, - int socket, unsigned requestedSize); -unsigned increaseReceiveBufferTo(UsageEnvironment& env, - int socket, unsigned requestedSize); - -Boolean socketJoinGroup(UsageEnvironment& env, int socket, - netAddressBits groupAddress); -Boolean socketLeaveGroup(UsageEnvironment&, int socket, - netAddressBits groupAddress); - -// source-specific multicast join/leave -Boolean socketJoinGroupSSM(UsageEnvironment& env, int socket, - netAddressBits groupAddress, - netAddressBits sourceFilterAddr); -Boolean socketLeaveGroupSSM(UsageEnvironment&, int socket, - netAddressBits groupAddress, - netAddressBits sourceFilterAddr); - -Boolean getSourcePort(UsageEnvironment& env, int socket, Port& port); - -netAddressBits ourSourceAddressForMulticast(UsageEnvironment& env); // in network order - -// IP addresses of our sending and receiving interfaces. (By default, these -// are INADDR_ANY (i.e., 0), specifying the default interface.) -extern netAddressBits SendingInterfaceAddr; -extern netAddressBits ReceivingInterfaceAddr; -extern netAddressBits ReceivingSocketAddr; - -// Allocates a randomly-chosen IPv4 SSM (multicast) address: -netAddressBits chooseRandomIPv4SSMAddress(UsageEnvironment& env); - -// Returns a simple "hh:mm:ss" string, for use in debugging output (e.g.) -char const* timestampString(); - - -#ifdef HAVE_SOCKADDR_LEN -#define SET_SOCKADDR_SIN_LEN(var) var.sin_len = sizeof var -#else -#define SET_SOCKADDR_SIN_LEN(var) -#endif - -#define MAKE_SOCKADDR_IN(var,adr,prt) /*adr,prt must be in network order*/\ - struct sockaddr_in var;\ - var.sin_family = AF_INET;\ - var.sin_addr.s_addr = (adr);\ - var.sin_port = (prt);\ - SET_SOCKADDR_SIN_LEN(var); - - -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(IMN_PIM) -// For Windoze, we need to implement our own gettimeofday() -extern int gettimeofday(struct timeval*, int*); -#endif - -// The following are implemented in inet.c: -extern "C" netAddressBits our_inet_addr(char const*); -extern "C" char* our_inet_ntoa(struct in_addr); -extern "C" struct hostent* our_gethostbyname(char* name); -extern "C" void our_srandom(int x); -extern "C" long our_random(); -extern "C" u_int32_t our_random32(); // because "our_random()" returns a 31-bit number - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/IOHandlers.hh b/mythtv/libs/libmythlivemedia/groupsock/include/IOHandlers.hh deleted file mode 100644 index 7f3a920907f..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/IOHandlers.hh +++ /dev/null @@ -1,31 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-1997 Live Networks, Inc. All rights reserved. -// IO event handlers -// C++ header - -#ifndef _IO_HANDLERS_HH -#define _IO_HANDLERS_HH - -#ifndef _NET_INTERFACE_HH -#include "NetInterface.hh" -#endif - -// Handles incoming data on sockets: -void socketReadHandler(Socket* sock, int mask); - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/NetAddress.hh b/mythtv/libs/libmythlivemedia/groupsock/include/NetAddress.hh deleted file mode 100644 index 3929a07c176..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/NetAddress.hh +++ /dev/null @@ -1,146 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-2001 Live Networks, Inc. All rights reserved. -// Network Addresses -// C++ header - -#ifndef _NET_ADDRESS_HH -#define _NET_ADDRESS_HH - -#ifndef _HASH_TABLE_HH -#include "HashTable.hh" -#endif - -#ifndef _NET_COMMON_H -#include "NetCommon.h" -#endif - -#ifndef _USAGE_ENVIRONMENT_HH -#include "UsageEnvironment.hh" -#endif - -// Definition of a type representing a low-level network address. -// At present, this is 32-bits, for IPv4. Later, generalize it, -// to allow for IPv6. -typedef u_int32_t netAddressBits; - -class NetAddress { - public: - NetAddress(u_int8_t const* data, - unsigned length = 4 /* default: 32 bits */); - NetAddress(unsigned length = 4); // sets address data to all-zeros - NetAddress(NetAddress const& orig); - NetAddress& operator=(NetAddress const& rightSide); - virtual ~NetAddress(); - - unsigned length() const { return fLength; } - u_int8_t const* data() const // always in network byte order - { return fData; } - - private: - void assign(u_int8_t const* data, unsigned length); - void clean(); - - unsigned fLength; - u_int8_t* fData; -}; - -class NetAddressList { - public: - NetAddressList(char const* hostname); - NetAddressList(NetAddressList const& orig); - NetAddressList& operator=(NetAddressList const& rightSide); - virtual ~NetAddressList(); - - unsigned numAddresses() const { return fNumAddresses; } - - NetAddress const* firstAddress() const; - - // Used to iterate through the addresses in a list: - class Iterator { - public: - Iterator(NetAddressList const& addressList); - NetAddress const* nextAddress(); // NULL iff none - private: - NetAddressList const& fAddressList; - unsigned fNextIndex; - }; - - private: - void assign(netAddressBits numAddresses, NetAddress** addressArray); - void clean(); - - friend class Iterator; - unsigned fNumAddresses; - NetAddress** fAddressArray; -}; - -typedef u_int16_t portNumBits; - -class Port { - public: - Port(portNumBits num /* in host byte order */); - - portNumBits num() const // in network byte order - { return fPortNum; } - - private: - portNumBits fPortNum; // stored in network byte order -#ifdef IRIX - portNumBits filler; // hack to overcome a bug in IRIX C++ compiler -#endif -}; - -UsageEnvironment& operator<<(UsageEnvironment& s, const Port& p); - - -// A generic table for looking up objects by (address1, address2, port) -class AddressPortLookupTable { - public: - AddressPortLookupTable(); - virtual ~AddressPortLookupTable(); - - void* Add(netAddressBits address1, netAddressBits address2, - Port port, void* value); - // Returns the old value if different, otherwise 0 - Boolean Remove(netAddressBits address1, netAddressBits address2, - Port port); - void* Lookup(netAddressBits address1, netAddressBits address2, - Port port); - // Returns 0 if not found - - // Used to iterate through the entries in the table - class Iterator { - public: - Iterator(AddressPortLookupTable& table); - virtual ~Iterator(); - - void* next(); // NULL iff none - - private: - HashTable::Iterator* fIter; - }; - - private: - friend class Iterator; - HashTable* fTable; -}; - - -Boolean IsMulticastAddress(netAddressBits address); - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/NetCommon.h b/mythtv/libs/libmythlivemedia/groupsock/include/NetCommon.h deleted file mode 100644 index 7974e8e491d..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/NetCommon.h +++ /dev/null @@ -1,98 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -/* "groupsock" interface - * Copyright (c) 1996-2003 Live Networks, Inc. All rights reserved. - * Common include files, typically used for networking - */ - -#ifndef _NET_COMMON_H -#define _NET_COMMON_H - -#if defined(IMN_PIM) -#include "IMN_PIMNetCommon.h" - -#elif defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_WCE) -/* Windows */ -#if defined(WINNT) || defined(_WINNT) || defined(__BORLANDC__) || defined(__MINGW32__) || defined(_WIN32_WCE) -#define _MSWSOCK_ -#include -#include -#endif -#include -#include - -#define closeSocket closesocket -#define EWOULDBLOCK WSAEWOULDBLOCK - -#if defined(_WIN32_WCE) -#define NO_STRSTREAM 1 -#endif - -/* Definitions of size-specific types: */ -typedef __int64 int64_t; -typedef unsigned __int64 u_int64_t; -typedef unsigned u_int32_t; -typedef unsigned short u_int16_t; -typedef unsigned char u_int8_t; - -#elif defined(VXWORKS) -/* VxWorks */ -#include -#include -#include -#include -#include -#include -#include - -typedef unsigned int u_int32_t; -typedef unsigned short u_int16_t; -typedef unsigned char u_int8_t; - -#else -/* Unix */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(_QNX4) -#include -#include -#endif - -#define closeSocket close - -#ifdef SOLARIS -#define u_int64_t uint64_t -#define u_int32_t uint32_t -#define u_int16_t uint16_t -#define u_int8_t uint8_t -#endif -#endif - -#ifndef SOCKLEN_T -#define SOCKLEN_T int -#endif - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/NetInterface.hh b/mythtv/libs/libmythlivemedia/groupsock/include/NetInterface.hh deleted file mode 100644 index bbe881cd4fa..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/NetInterface.hh +++ /dev/null @@ -1,150 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-2001 Live Networks, Inc. All rights reserved. -// Network Interfaces -// C++ header - -#ifndef _NET_INTERFACE_HH -#define _NET_INTERFACE_HH - -#ifndef _NET_ADDRESS_HH -#include "NetAddress.hh" -#endif - -class NetInterface { -public: - virtual ~NetInterface(); - - static UsageEnvironment* DefaultUsageEnvironment; - // if non-NULL, used for each new interfaces - -protected: - NetInterface(); // virtual base class -}; - -class DirectedNetInterface: public NetInterface { -public: - virtual ~DirectedNetInterface(); - - virtual Boolean write(unsigned char* data, unsigned numBytes) = 0; - - virtual Boolean SourceAddrOKForRelaying(UsageEnvironment& env, - unsigned addr) = 0; - -protected: - DirectedNetInterface(); // virtual base class -}; - -class DirectedNetInterfaceSet { -public: - DirectedNetInterfaceSet(); - virtual ~DirectedNetInterfaceSet(); - - DirectedNetInterface* Add(DirectedNetInterface const* interf); - // Returns the old value if different, otherwise 0 - Boolean Remove(DirectedNetInterface const* interf); - - Boolean IsEmpty() { return fTable->IsEmpty(); } - - // Used to iterate through the interfaces in the set - class Iterator { - public: - Iterator(DirectedNetInterfaceSet& interfaces); - virtual ~Iterator(); - - DirectedNetInterface* next(); // NULL iff none - - private: - HashTable::Iterator* fIter; - }; - -private: - friend class Iterator; - HashTable* fTable; -}; - -class Socket: public NetInterface { -public: - virtual ~Socket(); - - virtual Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize, - unsigned& bytesRead, - struct sockaddr_in& fromAddress) = 0; - // Returns False on error; resultData == NULL if data ignored - - int socketNum() const { return fSocketNum; } - - Port port() const { - return fPort; - } - - UsageEnvironment& env() const { return fEnv; } - - static int DebugLevel; - -protected: - Socket(UsageEnvironment& env, Port port, - Boolean setLoopback = True); // virtual base class - - Boolean changePort(Port newPort); // will also cause socketNum() to change - -private: - int fSocketNum; - UsageEnvironment& fEnv; - Port fPort; - Boolean fSetLoopback; -}; - -UsageEnvironment& operator<<(UsageEnvironment& s, const Socket& sock); - -// A data structure for looking up a Socket by port: - -class SocketLookupTable { -public: - virtual ~SocketLookupTable(); - - Socket* Fetch(UsageEnvironment& env, Port port, Boolean& isNew); - // Creates a new Socket if none already exists - Boolean Remove(Socket const* sock); - -protected: - SocketLookupTable(); // abstract base class - virtual Socket* CreateNew(UsageEnvironment& env, Port port) = 0; - -private: - HashTable* fTable; -}; - -// A data structure for counting traffic: - -class NetInterfaceTrafficStats { -public: - NetInterfaceTrafficStats(); - - void countPacket(unsigned packetSize); - - float totNumPackets() const {return fTotNumPackets;} - float totNumBytes() const {return fTotNumBytes;} - - Boolean haveSeenTraffic() const; - -private: - float fTotNumPackets; - float fTotNumBytes; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/TunnelEncaps.hh b/mythtv/libs/libmythlivemedia/groupsock/include/TunnelEncaps.hh deleted file mode 100644 index f5b5edb62fc..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/TunnelEncaps.hh +++ /dev/null @@ -1,101 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "mTunnel" multicast access service -// Copyright (c) 1996-1998 Live Networks, Inc. All rights reserved. -// Encapsulation trailer for tunnels -// C++ header - -#ifndef _TUNNEL_ENCAPS_HH -#define _TUNNEL_ENCAPS_HH - -#ifndef _NET_ADDRESS_HH -#include "NetAddress.hh" -#endif - -typedef u_int16_t Cookie; - -class TunnelEncapsulationTrailer { - // The trailer is layed out as follows: - // bytes 0-1: source 'cookie' - // bytes 2-3: destination 'cookie' - // bytes 4-7: address - // bytes 8-9: port - // byte 10: ttl - // byte 11: command - - // Optionally, there may also be a 4-byte 'auxilliary address' - // (e.g., for 'source-specific multicast' preceding this) - // bytes -4 through -1: auxilliary address - - public: - Cookie& srcCookie() - { return *(Cookie*)byteOffset(0); } - Cookie& dstCookie() - { return *(Cookie*)byteOffset(2); } - u_int32_t& address() - { return *(u_int32_t*)byteOffset(4); } - Port& port() - { return *(Port*)byteOffset(8); } - u_int8_t& ttl() - { return *(u_int8_t*)byteOffset(10); } - u_int8_t& command() - { return *(u_int8_t*)byteOffset(11); } - - u_int32_t& auxAddress() - { return *(u_int32_t*)byteOffset(-4); } - - private: - inline char* byteOffset(int charIndex) - { return ((char*)this) + charIndex; } -}; - -const unsigned TunnelEncapsulationTrailerSize = 12; // bytes -const unsigned TunnelEncapsulationTrailerAuxSize = 4; // bytes -const unsigned TunnelEncapsulationTrailerMaxSize - = TunnelEncapsulationTrailerSize + TunnelEncapsulationTrailerAuxSize; - -// Command codes: -// 0: unused -const u_int8_t TunnelDataCmd = 1; -const u_int8_t TunnelJoinGroupCmd = 2; -const u_int8_t TunnelLeaveGroupCmd = 3; -const u_int8_t TunnelTearDownCmd = 4; -const u_int8_t TunnelProbeCmd = 5; -const u_int8_t TunnelProbeAckCmd = 6; -const u_int8_t TunnelProbeNackCmd = 7; -const u_int8_t TunnelJoinRTPGroupCmd = 8; -const u_int8_t TunnelLeaveRTPGroupCmd = 9; -// 0x0A through 0x10: currently unused. -const u_int8_t TunnelExtensionFlag = 0x80; // a flag, not a cmd code -const u_int8_t TunnelDataAuxCmd - = (TunnelExtensionFlag|TunnelDataCmd); -const u_int8_t TunnelJoinGroupAuxCmd - = (TunnelExtensionFlag|TunnelJoinGroupCmd); -const u_int8_t TunnelLeaveGroupAuxCmd - = (TunnelExtensionFlag|TunnelLeaveGroupCmd); -// Note: the TearDown, Probe, ProbeAck, ProbeNack cmds have no Aux version -// 0x84 through 0x87: currently unused. -const u_int8_t TunnelJoinRTPGroupAuxCmd - = (TunnelExtensionFlag|TunnelJoinRTPGroupCmd); -const u_int8_t TunnelLeaveRTPGroupAuxCmd - = (TunnelExtensionFlag|TunnelLeaveRTPGroupCmd); -// 0x8A through 0xFF: currently unused - -inline Boolean TunnelIsAuxCmd(u_int8_t cmd) { - return (cmd&TunnelExtensionFlag) != 0; -} - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/include/groupsock_version.hh b/mythtv/libs/libmythlivemedia/groupsock/include/groupsock_version.hh deleted file mode 100644 index 7339badda53..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/include/groupsock_version.hh +++ /dev/null @@ -1,10 +0,0 @@ -// Version information for the "groupsock" library -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. - -#ifndef _GROUPSOCK_VERSION_HH -#define _GROUPSOCK_VERSION_HH - -#define GROUPSOCK_LIBRARY_VERSION_STRING "2006.05.17" -#define GROUPSOCK_LIBRARY_VERSION_INT 1147824000 - -#endif diff --git a/mythtv/libs/libmythlivemedia/groupsock/inet.c b/mythtv/libs/libmythlivemedia/groupsock/inet.c deleted file mode 100644 index f25b38bc7d9..00000000000 --- a/mythtv/libs/libmythlivemedia/groupsock/inet.c +++ /dev/null @@ -1,464 +0,0 @@ -/* Some systems (e.g., SunOS) have header files that erroneously declare - * inet_addr(), inet_ntoa() and gethostbyname() as taking no arguments. - * This confuses C++. To overcome this, we use our own routines, - * implemented in C. - */ - -#ifndef _NET_COMMON_H -#include "NetCommon.h" -#endif - -#include - -#ifdef VXWORKS -#include -#endif - -unsigned our_inet_addr(cp) - char const* cp; -{ - return inet_addr(cp); -} - -char * -our_inet_ntoa(in) - struct in_addr in; -{ -#ifndef VXWORKS - return inet_ntoa(in); -#else - /* according the man pages of inet_ntoa : - - NOTES - The return value from inet_ntoa() points to a buffer which - is overwritten on each call. This buffer is implemented as - thread-specific data in multithreaded applications. - - the vxworks version of inet_ntoa allocates a buffer for each - ip address string, and does not reuse the same buffer. - - this is merely to simulate the same behaviour (not multithread - safe though): - */ - static char result[INET_ADDR_LEN]; - inet_ntoa_b(in, result); - return(result); -#endif -} - -#if defined(__WIN32__) || defined(_WIN32) -#ifndef IMN_PIM -#define WS_VERSION_CHOICE1 0x202/*MAKEWORD(2,2)*/ -#define WS_VERSION_CHOICE2 0x101/*MAKEWORD(1,1)*/ -int initializeWinsockIfNecessary(void) { - /* We need to call an initialization routine before - * we can do anything with winsock. (How fucking lame!): - */ - static int _haveInitializedWinsock = 0; - WSADATA wsadata; - - if (!_haveInitializedWinsock) { - if ((WSAStartup(WS_VERSION_CHOICE1, &wsadata) != 0) - && ((WSAStartup(WS_VERSION_CHOICE2, &wsadata)) != 0)) { - return 0; /* error in initialization */ - } - if ((wsadata.wVersion != WS_VERSION_CHOICE1) - && (wsadata.wVersion != WS_VERSION_CHOICE2)) { - WSACleanup(); - return 0; /* desired Winsock version was not available */ - } - _haveInitializedWinsock = 1; - } - - return 1; -} -#else -int initializeWinsockIfNecessary(void) { return 1; } -#endif -#else -#define initializeWinsockIfNecessary() 1 -#endif - -#ifndef NULL -#define NULL 0 -#endif - -#if !defined(VXWORKS) -struct hostent* our_gethostbyname(name) - char* name; -{ - if (!initializeWinsockIfNecessary()) return NULL; - - return (struct hostent*) gethostbyname(name); -} -#endif - -#ifdef USE_SYSTEM_RANDOM -#include -long our_random() { -#if defined(__WIN32__) || defined(_WIN32) - return rand(); -#else - return random(); -#endif -} -void our_srandom(unsigned int x) { -#if defined(__WIN32__) || defined(_WIN32) - return srand(x); -#else - return srandom(x); -#endif -} -#else -/* - * random.c: - * - * An improved random number generation package. In addition to the standard - * rand()/srand() like interface, this package also has a special state info - * interface. The our_initstate() routine is called with a seed, an array of - * bytes, and a count of how many bytes are being passed in; this array is - * then initialized to contain information for random number generation with - * that much state information. Good sizes for the amount of state - * information are 32, 64, 128, and 256 bytes. The state can be switched by - * calling the our_setstate() routine with the same array as was initiallized - * with our_initstate(). By default, the package runs with 128 bytes of state - * information and generates far better random numbers than a linear - * congruential generator. If the amount of state information is less than - * 32 bytes, a simple linear congruential R.N.G. is used. - * - * Internally, the state information is treated as an array of longs; the - * zeroeth element of the array is the type of R.N.G. being used (small - * integer); the remainder of the array is the state information for the - * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of - * state information, which will allow a degree seven polynomial. (Note: - * the zeroeth word of state information also has some other information - * stored in it -- see our_setstate() for details). - * - * The random number generation technique is a linear feedback shift register - * approach, employing trinomials (since there are fewer terms to sum up that - * way). In this approach, the least significant bit of all the numbers in - * the state table will act as a linear feedback shift register, and will - * have period 2^deg - 1 (where deg is the degree of the polynomial being - * used, assuming that the polynomial is irreducible and primitive). The - * higher order bits will have longer periods, since their values are also - * influenced by pseudo-random carries out of the lower bits. The total - * period of the generator is approximately deg*(2**deg - 1); thus doubling - * the amount of state information has a vast influence on the period of the - * generator. Note: the deg*(2**deg - 1) is an approximation only good for - * large deg, when the period of the shift register is the dominant factor. - * With deg equal to seven, the period is actually much longer than the - * 7*(2**7 - 1) predicted by this formula. - */ - -/* - * For each of the currently supported random number generators, we have a - * break value on the amount of state information (you need at least this - * many bytes of state info to support this random number generator), a degree - * for the polynomial (actually a trinomial) that the R.N.G. is based on, and - * the separation between the two lower order coefficients of the trinomial. - */ -#define TYPE_0 0 /* linear congruential */ -#define BREAK_0 8 -#define DEG_0 0 -#define SEP_0 0 - -#define TYPE_1 1 /* x**7 + x**3 + 1 */ -#define BREAK_1 32 -#define DEG_1 7 -#define SEP_1 3 - -#define TYPE_2 2 /* x**15 + x + 1 */ -#define BREAK_2 64 -#define DEG_2 15 -#define SEP_2 1 - -#define TYPE_3 3 /* x**31 + x**3 + 1 */ -#define BREAK_3 128 -#define DEG_3 31 -#define SEP_3 3 - -#define TYPE_4 4 /* x**63 + x + 1 */ -#define BREAK_4 256 -#define DEG_4 63 -#define SEP_4 1 - -/* - * Array versions of the above information to make code run faster -- - * relies on fact that TYPE_i == i. - */ -#define MAX_TYPES 5 /* max number of types above */ - -static int const degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; -static int const seps [MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; - -/* - * Initially, everything is set up as if from: - * - * our_initstate(1, &randtbl, 128); - * - * Note that this initialization takes advantage of the fact that srandom() - * advances the front and rear pointers 10*rand_deg times, and hence the - * rear pointer which starts at 0 will also end up at zero; thus the zeroeth - * element of the state information, which contains info about the current - * position of the rear pointer is just - * - * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3. - */ - -static long randtbl[DEG_3 + 1] = { - TYPE_3, - 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5, - 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, - 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, - 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, - 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b, - 0x27fb47b9, -}; - -/* - * fptr and rptr are two pointers into the state info, a front and a rear - * pointer. These two pointers are always rand_sep places aparts, as they - * cycle cyclically through the state information. (Yes, this does mean we - * could get away with just one pointer, but the code for random() is more - * efficient this way). The pointers are left positioned as they would be - * from the call - * - * our_initstate(1, randtbl, 128); - * - * (The position of the rear pointer, rptr, is really 0 (as explained above - * in the initialization of randtbl) because the state table pointer is set - * to point to randtbl[1] (as explained below). - */ -static long* fptr = &randtbl[SEP_3 + 1]; -static long* rptr = &randtbl[1]; - -/* - * The following things are the pointer to the state information table, the - * type of the current generator, the degree of the current polynomial being - * used, and the separation between the two pointers. Note that for efficiency - * of random(), we remember the first location of the state information, not - * the zeroeth. Hence it is valid to access state[-1], which is used to - * store the type of the R.N.G. Also, we remember the last location, since - * this is more efficient than indexing every time to find the address of - * the last element to see if the front and rear pointers have wrapped. - */ -static long *state = &randtbl[1]; -static int rand_type = TYPE_3; -static int rand_deg = DEG_3; -static int rand_sep = SEP_3; -static long* end_ptr = &randtbl[DEG_3 + 1]; - -/* - * srandom: - * - * Initialize the random number generator based on the given seed. If the - * type is the trivial no-state-information type, just remember the seed. - * Otherwise, initializes state[] based on the given "seed" via a linear - * congruential generator. Then, the pointers are set to known locations - * that are exactly rand_sep places apart. Lastly, it cycles the state - * information a given number of times to get rid of any initial dependencies - * introduced by the L.C.R.N.G. Note that the initialization of randtbl[] - * for default usage relies on values produced by this routine. - */ -long our_random(void); /*forward*/ -void -our_srandom(unsigned int x) -{ - register int i; - - if (rand_type == TYPE_0) - state[0] = x; - else { - state[0] = x; - for (i = 1; i < rand_deg; i++) - state[i] = 1103515245 * state[i - 1] + 12345; - fptr = &state[rand_sep]; - rptr = &state[0]; - for (i = 0; i < 10 * rand_deg; i++) - (void)our_random(); - } -} - -/* - * our_initstate: - * - * Initialize the state information in the given array of n bytes for future - * random number generation. Based on the number of bytes we are given, and - * the break values for the different R.N.G.'s, we choose the best (largest) - * one we can and set things up for it. srandom() is then called to - * initialize the state information. - * - * Note that on return from srandom(), we set state[-1] to be the type - * multiplexed with the current value of the rear pointer; this is so - * successive calls to our_initstate() won't lose this information and will be - * able to restart with our_setstate(). - * - * Note: the first thing we do is save the current state, if any, just like - * our_setstate() so that it doesn't matter when our_initstate is called. - * - * Returns a pointer to the old state. - */ -char * -our_initstate(seed, arg_state, n) - unsigned int seed; /* seed for R.N.G. */ - char *arg_state; /* pointer to state array */ - int n; /* # bytes of state info */ -{ - register char *ostate = (char *)(&state[-1]); - - if (rand_type == TYPE_0) - state[-1] = rand_type; - else - state[-1] = MAX_TYPES * (rptr - state) + rand_type; - if (n < BREAK_0) { -#ifdef DEBUG - (void)fprintf(stderr, - "random: not enough state (%d bytes); ignored.\n", n); -#endif - return(0); - } - if (n < BREAK_1) { - rand_type = TYPE_0; - rand_deg = DEG_0; - rand_sep = SEP_0; - } else if (n < BREAK_2) { - rand_type = TYPE_1; - rand_deg = DEG_1; - rand_sep = SEP_1; - } else if (n < BREAK_3) { - rand_type = TYPE_2; - rand_deg = DEG_2; - rand_sep = SEP_2; - } else if (n < BREAK_4) { - rand_type = TYPE_3; - rand_deg = DEG_3; - rand_sep = SEP_3; - } else { - rand_type = TYPE_4; - rand_deg = DEG_4; - rand_sep = SEP_4; - } - state = &(((long *)arg_state)[1]); /* first location */ - end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ - our_srandom(seed); - if (rand_type == TYPE_0) - state[-1] = rand_type; - else - state[-1] = MAX_TYPES*(rptr - state) + rand_type; - return(ostate); -} - -/* - * our_setstate: - * - * Restore the state from the given state array. - * - * Note: it is important that we also remember the locations of the pointers - * in the current state information, and restore the locations of the pointers - * from the old state information. This is done by multiplexing the pointer - * location into the zeroeth word of the state information. - * - * Note that due to the order in which things are done, it is OK to call - * our_setstate() with the same state as the current state. - * - * Returns a pointer to the old state information. - */ -char * -our_setstate(arg_state) - char *arg_state; -{ - register long *new_state = (long *)arg_state; - register int type = new_state[0] % MAX_TYPES; - register int rear = new_state[0] / MAX_TYPES; - char *ostate = (char *)(&state[-1]); - - if (rand_type == TYPE_0) - state[-1] = rand_type; - else - state[-1] = MAX_TYPES * (rptr - state) + rand_type; - switch(type) { - case TYPE_0: - case TYPE_1: - case TYPE_2: - case TYPE_3: - case TYPE_4: - rand_type = type; - rand_deg = degrees[type]; - rand_sep = seps[type]; - break; - default: -#ifdef DEBUG - (void)fprintf(stderr, - "random: state info corrupted; not changed.\n"); -#endif - break; - } - state = &new_state[1]; - if (rand_type != TYPE_0) { - rptr = &state[rear]; - fptr = &state[(rear + rand_sep) % rand_deg]; - } - end_ptr = &state[rand_deg]; /* set end_ptr too */ - return(ostate); -} - -/* - * random: - * - * If we are using the trivial TYPE_0 R.N.G., just do the old linear - * congruential bit. Otherwise, we do our fancy trinomial stuff, which is - * the same in all the other cases due to all the global variables that have - * been set up. The basic operation is to add the number at the rear pointer - * into the one at the front pointer. Then both pointers are advanced to - * the next location cyclically in the table. The value returned is the sum - * generated, reduced to 31 bits by throwing away the "least random" low bit. - * - * Note: the code takes advantage of the fact that both the front and - * rear pointers can't wrap on the same call by not testing the rear - * pointer if the front one has wrapped. - * - * Returns a 31-bit random number. - */ -long -our_random() -{ - long i; - - if (rand_type == TYPE_0) - i = state[0] = (state[0] * 1103515245 + 12345) & 0x7fffffff; - else { - *fptr += *rptr; - i = (*fptr >> 1) & 0x7fffffff; /* chucking least random bit */ - if (++fptr >= end_ptr) { - fptr = state; - ++rptr; - } else if (++rptr >= end_ptr) - rptr = state; - } - return(i); -} -#endif - -u_int32_t our_random32() { - // Return a 32-bit random number. - // Because "our_random()" returns a 31-bit random number, we call it a second - // time, to generate the high bit: - long random1 = our_random(); - long random2 = our_random(); - return (u_int32_t)((random2<<31) | random1); -} - -#ifdef USE_OUR_BZERO -#ifndef __bzero -void -__bzero (to, count) - char *to; - int count; -{ - while (count-- > 0) - { - *to++ = 0; - } -} -#endif -#endif diff --git a/mythtv/libs/libmythlivemedia/libmythlivemedia.pro b/mythtv/libs/libmythlivemedia/libmythlivemedia.pro deleted file mode 100644 index 546083cb2e6..00000000000 --- a/mythtv/libs/libmythlivemedia/libmythlivemedia.pro +++ /dev/null @@ -1,307 +0,0 @@ -include ( ../../settings.pro ) - -TEMPLATE = lib -TARGET = mythlivemedia-$$LIBVERSION -CONFIG += thread dll warn_off -target.path = $${LIBDIR} -INSTALLS = target - -INCLUDEPATH += BasicUsageEnvironment/include -INCLUDEPATH += groupsock/include -INCLUDEPATH += liveMedia liveMedia/include -INCLUDEPATH += UsageEnvironment/include - -LIBS += $$EXTRA_LIBS - -DEFINES += SOCKLEN_T=socklen_t - -QMAKE_CLEAN += $(TARGET) $(TARGETA) $(TARGETD) $(TARGET0) $(TARGET1) $(TARGET2) - -# Input -using_live { - - HEADERS += BasicUsageEnvironment/include/BasicHashTable.hh - HEADERS += BasicUsageEnvironment/include/BasicUsageEnvironment.hh - HEADERS += BasicUsageEnvironment/include/BasicUsageEnvironment0.hh - HEADERS += BasicUsageEnvironment/include/BasicUsageEnvironment_version.hh - HEADERS += BasicUsageEnvironment/include/DelayQueue.hh - HEADERS += BasicUsageEnvironment/include/HandlerSet.hh - - SOURCES += BasicUsageEnvironment/BasicHashTable.cpp - SOURCES += BasicUsageEnvironment/BasicTaskScheduler0.cpp - SOURCES += BasicUsageEnvironment/BasicTaskScheduler.cpp - SOURCES += BasicUsageEnvironment/BasicUsageEnvironment0.cpp - SOURCES += BasicUsageEnvironment/BasicUsageEnvironment.cpp - SOURCES += BasicUsageEnvironment/DelayQueue.cpp - - - HEADERS += groupsock/include/GroupEId.hh - HEADERS += groupsock/include/Groupsock.hh - HEADERS += groupsock/include/GroupsockHelper.hh - HEADERS += groupsock/include/IOHandlers.hh - HEADERS += groupsock/include/NetAddress.hh - HEADERS += groupsock/include/NetCommon.h - HEADERS += groupsock/include/NetInterface.hh - HEADERS += groupsock/include/TunnelEncaps.hh - HEADERS += groupsock/include/groupsock_version.hh - - SOURCES += groupsock/GroupEId.cpp - SOURCES += groupsock/Groupsock.cpp - SOURCES += groupsock/GroupsockHelper.cpp - SOURCES += groupsock/inet.c - SOURCES += groupsock/IOHandlers.cpp - SOURCES += groupsock/NetAddress.cpp - SOURCES += groupsock/NetInterface.cpp - - - HEADERS += UsageEnvironment/include/Boolean.hh - HEADERS += UsageEnvironment/include/HashTable.hh - HEADERS += UsageEnvironment/include/UsageEnvironment.hh - HEADERS += UsageEnvironment/include/UsageEnvironment_version.hh - HEADERS += UsageEnvironment/include/strDup.hh - - SOURCES += UsageEnvironment/HashTable.cpp - SOURCES += UsageEnvironment/strDup.cpp - SOURCES += UsageEnvironment/UsageEnvironment.cpp - - - HEADERS += liveMedia/BitVector.hh - HEADERS += liveMedia/H263plusVideoStreamParser.hh - HEADERS += liveMedia/MP3ADUdescriptor.hh - HEADERS += liveMedia/MP3Internals.hh - HEADERS += liveMedia/MP3InternalsHuffman.hh - HEADERS += liveMedia/MP3StreamState.hh - HEADERS += liveMedia/MPEGVideoStreamParser.hh - HEADERS += liveMedia/StreamParser.hh - HEADERS += liveMedia/our_md5.h - HEADERS += liveMedia/rtcp_from_spec.h - - HEADERS += liveMedia/include/AC3AudioRTPSink.hh - HEADERS += liveMedia/include/AC3AudioRTPSource.hh - HEADERS += liveMedia/include/AC3AudioStreamFramer.hh - HEADERS += liveMedia/include/ADTSAudioFileServerMediaSubsession.hh - HEADERS += liveMedia/include/ADTSAudioFileSource.hh - HEADERS += liveMedia/include/AMRAudioFileServerMediaSubsession.hh - HEADERS += liveMedia/include/AMRAudioFileSink.hh - HEADERS += liveMedia/include/AMRAudioFileSource.hh - HEADERS += liveMedia/include/AMRAudioRTPSink.hh - HEADERS += liveMedia/include/AMRAudioRTPSource.hh - HEADERS += liveMedia/include/AMRAudioSource.hh - HEADERS += liveMedia/include/AVIFileSink.hh - HEADERS += liveMedia/include/AudioInputDevice.hh - HEADERS += liveMedia/include/AudioRTPSink.hh - HEADERS += liveMedia/include/Base64.hh - HEADERS += liveMedia/include/BasicUDPSink.hh - HEADERS += liveMedia/include/BasicUDPSource.hh - HEADERS += liveMedia/include/ByteStreamFileSource.hh - HEADERS += liveMedia/include/ByteStreamMultiFileSource.hh - HEADERS += liveMedia/include/DarwinInjector.hh - HEADERS += liveMedia/include/DeviceSource.hh - HEADERS += liveMedia/include/DigestAuthentication.hh - HEADERS += liveMedia/include/FileServerMediaSubsession.hh - HEADERS += liveMedia/include/FileSink.hh - HEADERS += liveMedia/include/FramedFileSource.hh - HEADERS += liveMedia/include/FramedFilter.hh - HEADERS += liveMedia/include/FramedSource.hh - HEADERS += liveMedia/include/GSMAudioRTPSink.hh - HEADERS += liveMedia/include/H261VideoRTPSource.hh - HEADERS += liveMedia/include/H263plusVideoFileServerMediaSubsession.hh - HEADERS += liveMedia/include/H263plusVideoRTPSink.hh - HEADERS += liveMedia/include/H263plusVideoRTPSource.hh - HEADERS += liveMedia/include/H263plusVideoStreamFramer.hh - HEADERS += liveMedia/include/H264VideoRTPSource.hh - HEADERS += liveMedia/include/HTTPSink.hh - HEADERS += liveMedia/include/InputFile.hh - HEADERS += liveMedia/include/JPEGVideoRTPSink.hh - HEADERS += liveMedia/include/JPEGVideoRTPSource.hh - HEADERS += liveMedia/include/JPEGVideoSource.hh - HEADERS += liveMedia/include/MP3ADU.hh - HEADERS += liveMedia/include/MP3ADURTPSink.hh - HEADERS += liveMedia/include/MP3ADURTPSource.hh - HEADERS += liveMedia/include/MP3ADUTranscoder.hh - HEADERS += liveMedia/include/MP3ADUinterleaving.hh - HEADERS += liveMedia/include/MP3AudioFileServerMediaSubsession.hh - HEADERS += liveMedia/include/MP3FileSource.hh - HEADERS += liveMedia/include/MP3HTTPSource.hh - HEADERS += liveMedia/include/MP3Transcoder.hh - HEADERS += liveMedia/include/MPEG1or2AudioRTPSink.hh - HEADERS += liveMedia/include/MPEG1or2AudioRTPSource.hh - HEADERS += liveMedia/include/MPEG1or2AudioStreamFramer.hh - HEADERS += liveMedia/include/MPEG1or2Demux.hh - HEADERS += liveMedia/include/MPEG1or2DemuxedElementaryStream.hh - HEADERS += liveMedia/include/MPEG1or2DemuxedServerMediaSubsession.hh - HEADERS += liveMedia/include/MPEG1or2FileServerDemux.hh - HEADERS += liveMedia/include/MPEG1or2VideoFileServerMediaSubsession.hh - HEADERS += liveMedia/include/MPEG1or2VideoHTTPSink.hh - HEADERS += liveMedia/include/MPEG1or2VideoRTPSink.hh - HEADERS += liveMedia/include/MPEG1or2VideoRTPSource.hh - HEADERS += liveMedia/include/MPEG1or2VideoStreamDiscreteFramer.hh - HEADERS += liveMedia/include/MPEG1or2VideoStreamFramer.hh - HEADERS += liveMedia/include/MPEG2TransportFileServerMediaSubsession.hh - HEADERS += liveMedia/include/MPEG2TransportStreamFramer.hh - HEADERS += liveMedia/include/MPEG2TransportStreamFromESSource.hh - HEADERS += liveMedia/include/MPEG2TransportStreamFromPESSource.hh - HEADERS += liveMedia/include/MPEG2TransportStreamMultiplexor.hh - HEADERS += liveMedia/include/MPEG4ESVideoRTPSink.hh - HEADERS += liveMedia/include/MPEG4ESVideoRTPSource.hh - HEADERS += liveMedia/include/MPEG4GenericRTPSink.hh - HEADERS += liveMedia/include/MPEG4GenericRTPSource.hh - HEADERS += liveMedia/include/MPEG4LATMAudioRTPSink.hh - HEADERS += liveMedia/include/MPEG4LATMAudioRTPSource.hh - HEADERS += liveMedia/include/MPEG4VideoFileServerMediaSubsession.hh - HEADERS += liveMedia/include/MPEG4VideoStreamDiscreteFramer.hh - HEADERS += liveMedia/include/MPEG4VideoStreamFramer.hh - HEADERS += liveMedia/include/MPEGVideoStreamFramer.hh - HEADERS += liveMedia/include/Media.hh - HEADERS += liveMedia/include/MediaSession.hh - HEADERS += liveMedia/include/MediaSink.hh - HEADERS += liveMedia/include/MediaSource.hh - HEADERS += liveMedia/include/MultiFramedRTPSink.hh - HEADERS += liveMedia/include/MultiFramedRTPSource.hh - HEADERS += liveMedia/include/OnDemandServerMediaSubsession.hh - HEADERS += liveMedia/include/OutputFile.hh - HEADERS += liveMedia/include/PassiveServerMediaSubsession.hh - HEADERS += liveMedia/include/PrioritizedRTPStreamSelector.hh - HEADERS += liveMedia/include/QCELPAudioRTPSource.hh - HEADERS += liveMedia/include/QuickTimeFileSink.hh - HEADERS += liveMedia/include/QuickTimeGenericRTPSource.hh - HEADERS += liveMedia/include/RTCP.hh - HEADERS += liveMedia/include/RTPInterface.hh - HEADERS += liveMedia/include/RTPSink.hh - HEADERS += liveMedia/include/RTPSource.hh - HEADERS += liveMedia/include/RTSPClient.hh - HEADERS += liveMedia/include/RTSPCommon.hh - HEADERS += liveMedia/include/RTSPServer.hh - HEADERS += liveMedia/include/SIPClient.hh - HEADERS += liveMedia/include/ServerMediaSession.hh - HEADERS += liveMedia/include/SimpleRTPSink.hh - HEADERS += liveMedia/include/SimpleRTPSource.hh - HEADERS += liveMedia/include/VideoRTPSink.hh - HEADERS += liveMedia/include/WAVAudioFileServerMediaSubsession.hh - HEADERS += liveMedia/include/WAVAudioFileSource.hh - HEADERS += liveMedia/include/liveMedia.hh - HEADERS += liveMedia/include/liveMedia_version.hh - HEADERS += liveMedia/include/uLawAudioFilter.hh - - SOURCES += liveMedia/AC3AudioRTPSink.cpp - SOURCES += liveMedia/AC3AudioRTPSource.cpp - SOURCES += liveMedia/AC3AudioStreamFramer.cpp - SOURCES += liveMedia/ADTSAudioFileServerMediaSubsession.cpp - SOURCES += liveMedia/ADTSAudioFileSource.cpp - SOURCES += liveMedia/AMRAudioFileServerMediaSubsession.cpp - SOURCES += liveMedia/AMRAudioFileSink.cpp - SOURCES += liveMedia/AMRAudioFileSource.cpp - SOURCES += liveMedia/AMRAudioRTPSink.cpp - SOURCES += liveMedia/AMRAudioRTPSource.cpp - SOURCES += liveMedia/AMRAudioSource.cpp - SOURCES += liveMedia/AudioInputDevice.cpp - SOURCES += liveMedia/AudioRTPSink.cpp - SOURCES += liveMedia/AVIFileSink.cpp - SOURCES += liveMedia/Base64.cpp - SOURCES += liveMedia/BasicUDPSink.cpp - SOURCES += liveMedia/BasicUDPSource.cpp - SOURCES += liveMedia/BitVector.cpp - SOURCES += liveMedia/ByteStreamFileSource.cpp - SOURCES += liveMedia/ByteStreamMultiFileSource.cpp - SOURCES += liveMedia/DarwinInjector.cpp - SOURCES += liveMedia/DeviceSource.cpp - SOURCES += liveMedia/DigestAuthentication.cpp - SOURCES += liveMedia/FileServerMediaSubsession.cpp - SOURCES += liveMedia/FileSink.cpp - SOURCES += liveMedia/FramedFileSource.cpp - SOURCES += liveMedia/FramedFilter.cpp - SOURCES += liveMedia/FramedSource.cpp - SOURCES += liveMedia/GSMAudioRTPSink.cpp - SOURCES += liveMedia/H261VideoRTPSource.cpp - SOURCES += liveMedia/H263plusVideoFileServerMediaSubsession.cpp - SOURCES += liveMedia/H263plusVideoRTPSink.cpp - SOURCES += liveMedia/H263plusVideoRTPSource.cpp - SOURCES += liveMedia/H263plusVideoStreamFramer.cpp - SOURCES += liveMedia/H263plusVideoStreamParser.cpp - SOURCES += liveMedia/H264VideoRTPSource.cpp - SOURCES += liveMedia/HTTPSink.cpp - SOURCES += liveMedia/InputFile.cpp - SOURCES += liveMedia/JPEGVideoRTPSink.cpp - SOURCES += liveMedia/JPEGVideoRTPSource.cpp - SOURCES += liveMedia/JPEGVideoSource.cpp - SOURCES += liveMedia/Media.cpp - SOURCES += liveMedia/MediaSession.cpp - SOURCES += liveMedia/MediaSink.cpp - SOURCES += liveMedia/MediaSource.cpp - SOURCES += liveMedia/MP3ADU.cpp - SOURCES += liveMedia/MP3ADUdescriptor.cpp - SOURCES += liveMedia/MP3ADUinterleaving.cpp - SOURCES += liveMedia/MP3ADURTPSink.cpp - SOURCES += liveMedia/MP3ADURTPSource.cpp - SOURCES += liveMedia/MP3ADUTranscoder.cpp - SOURCES += liveMedia/MP3AudioFileServerMediaSubsession.cpp - SOURCES += liveMedia/MP3FileSource.cpp - SOURCES += liveMedia/MP3HTTPSource.cpp - SOURCES += liveMedia/MP3Internals.cpp - SOURCES += liveMedia/MP3InternalsHuffman.cpp - SOURCES += liveMedia/MP3InternalsHuffmanTable.cpp - SOURCES += liveMedia/MP3StreamState.cpp - SOURCES += liveMedia/MP3Transcoder.cpp - SOURCES += liveMedia/MPEG1or2AudioRTPSink.cpp - SOURCES += liveMedia/MPEG1or2AudioRTPSource.cpp - SOURCES += liveMedia/MPEG1or2AudioStreamFramer.cpp - SOURCES += liveMedia/MPEG1or2Demux.cpp - SOURCES += liveMedia/MPEG1or2DemuxedElementaryStream.cpp - SOURCES += liveMedia/MPEG1or2DemuxedServerMediaSubsession.cpp - SOURCES += liveMedia/MPEG1or2FileServerDemux.cpp - SOURCES += liveMedia/MPEG1or2VideoFileServerMediaSubsession.cpp - SOURCES += liveMedia/MPEG1or2VideoHTTPSink.cpp - SOURCES += liveMedia/MPEG1or2VideoRTPSink.cpp - SOURCES += liveMedia/MPEG1or2VideoRTPSource.cpp - SOURCES += liveMedia/MPEG1or2VideoStreamDiscreteFramer.cpp - SOURCES += liveMedia/MPEG1or2VideoStreamFramer.cpp - SOURCES += liveMedia/MPEG2TransportFileServerMediaSubsession.cpp - SOURCES += liveMedia/MPEG2TransportStreamFramer.cpp - SOURCES += liveMedia/MPEG2TransportStreamFromESSource.cpp - SOURCES += liveMedia/MPEG2TransportStreamFromPESSource.cpp - SOURCES += liveMedia/MPEG2TransportStreamMultiplexor.cpp - SOURCES += liveMedia/MPEG4ESVideoRTPSink.cpp - SOURCES += liveMedia/MPEG4ESVideoRTPSource.cpp - SOURCES += liveMedia/MPEG4GenericRTPSink.cpp - SOURCES += liveMedia/MPEG4GenericRTPSource.cpp - SOURCES += liveMedia/MPEG4LATMAudioRTPSink.cpp - SOURCES += liveMedia/MPEG4LATMAudioRTPSource.cpp - SOURCES += liveMedia/MPEG4VideoFileServerMediaSubsession.cpp - SOURCES += liveMedia/MPEG4VideoStreamDiscreteFramer.cpp - SOURCES += liveMedia/MPEG4VideoStreamFramer.cpp - SOURCES += liveMedia/MPEGVideoStreamFramer.cpp - SOURCES += liveMedia/MPEGVideoStreamParser.cpp - SOURCES += liveMedia/MultiFramedRTPSink.cpp - SOURCES += liveMedia/MultiFramedRTPSource.cpp - SOURCES += liveMedia/OnDemandServerMediaSubsession.cpp - SOURCES += liveMedia/our_md5.c - SOURCES += liveMedia/our_md5hl.c - SOURCES += liveMedia/OutputFile.cpp - SOURCES += liveMedia/PassiveServerMediaSubsession.cpp - SOURCES += liveMedia/PrioritizedRTPStreamSelector.cpp - SOURCES += liveMedia/QCELPAudioRTPSource.cpp - SOURCES += liveMedia/QuickTimeFileSink.cpp - SOURCES += liveMedia/QuickTimeGenericRTPSource.cpp - SOURCES += liveMedia/RTCP.cpp - SOURCES += liveMedia/rtcp_from_spec.c - SOURCES += liveMedia/RTPInterface.cpp - SOURCES += liveMedia/RTPSink.cpp - SOURCES += liveMedia/RTPSource.cpp - SOURCES += liveMedia/RTSPClient.cpp - SOURCES += liveMedia/RTSPCommon.cpp - SOURCES += liveMedia/RTSPServer.cpp - SOURCES += liveMedia/ServerMediaSession.cpp - SOURCES += liveMedia/SimpleRTPSink.cpp - SOURCES += liveMedia/SimpleRTPSource.cpp - SOURCES += liveMedia/SIPClient.cpp - SOURCES += liveMedia/StreamParser.cpp - SOURCES += liveMedia/uLawAudioFilter.cpp - SOURCES += liveMedia/VideoRTPSink.cpp - SOURCES += liveMedia/WAVAudioFileServerMediaSubsession.cpp - SOURCES += liveMedia/WAVAudioFileSource.cpp -} - -#The following line was inserted by qt3to4 -QT -= core gui - -include ( ../libs-targetfix.pro ) diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioRTPSink.cpp deleted file mode 100644 index f126de44114..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioRTPSink.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for AC3 audio -// Implementation - -#include "AC3AudioRTPSink.hh" - -AC3AudioRTPSink::AC3AudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency) - : AudioRTPSink(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, "AC3") { -} - -AC3AudioRTPSink::~AC3AudioRTPSink() { -} - -AC3AudioRTPSink* -AC3AudioRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency) { - return new AC3AudioRTPSink(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency); -} - -Boolean AC3AudioRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - // (For now) allow at most 1 frame in a single packet: - return False; -} - -void AC3AudioRTPSink -::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - // Update the "NDU" header. - // Also set the "Data Unit Header" for the frame, because we - // have already allotted space for this, by virtue of the fact that - // (for now) we pack only one frame in each RTP packet: - unsigned char headers[2]; - headers[0] = numFramesUsedSoFar() + 1; - - Boolean isFragment = numRemainingBytes > 0 || fragmentationOffset > 0; - unsigned const totalFrameSize - = fragmentationOffset + numBytesInFrame + numRemainingBytes; - unsigned const fiveEighthsPoint = totalFrameSize/2 + totalFrameSize/8; - Boolean haveFiveEighths - = fragmentationOffset == 0 && numBytesInFrame >= fiveEighthsPoint; - headers[1] = (isFragment<<5)|(haveFiveEighths<<4); // F|B - // Note: TYP==0, RDT==0 ???, T==0 ??? - - setSpecialHeaderBytes(headers, sizeof headers); - - if (numRemainingBytes == 0) { - // This packet contains the last (or only) fragment of the frame. - // Set the RTP 'M' ('marker') bit: - setMarkerBit(); - } - - // Important: Also call our base class's doSpecialFrameHandling(), - // to set the packet's timestamp: - MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, - frameStart, numBytesInFrame, - frameTimestamp, - numRemainingBytes); -} - -unsigned AC3AudioRTPSink::specialHeaderSize() const { - // There's a 1 byte "NDU" header. - // There's also a 1-byte "Data Unit Header" preceding each frame in - // the RTP packet, but since we (for now) pack only one frame in - // each RTP packet, we also count this here: - return 1 + 1; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioRTPSource.cpp deleted file mode 100644 index 7b67c71a7f4..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioRTPSource.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// AC3 Audio RTP Sources -// Implementation - -#include "AC3AudioRTPSource.hh" - -AC3AudioRTPSource* -AC3AudioRTPSource::createNew(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new AC3AudioRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -AC3AudioRTPSource::AC3AudioRTPSource(UsageEnvironment& env, - Groupsock* rtpGS, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, rtpGS, - rtpPayloadFormat, rtpTimestampFrequency) { -} - -AC3AudioRTPSource::~AC3AudioRTPSource() { -} - -Boolean AC3AudioRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - unsigned char* headerStart = packet->data(); - unsigned packetSize = packet->dataSize(); - - // There's a 1-byte "NDU" header, containing the number of frames - // present in this RTP packet. - if (packetSize < 2) return False; - unsigned char numFrames = headerStart[0]; - if (numFrames == 0) return False; - - // TEMP: We can't currently handle packets containing > 1 frame ##### - if (numFrames > 1) { - envir() << "AC3AudioRTPSource::processSpecialHeader(): packet contains " - << numFrames << " frames (we can't handle this!)\n"; - return False; - } - - // We current can't handle packets that consist only of redundant data: - unsigned char typ_field = headerStart[1] >> 6; - if (typ_field >= 2) return False; - - fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame; - // whether the *previous* packet ended a frame - - // The RTP "M" (marker) bit indicates the last fragment of a frame: - fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); - - resultSpecialHeaderSize = 2; - return True; -} - -char const* AC3AudioRTPSource::MIMEtype() const { - return "audio/AC3"; -} - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioStreamFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioStreamFramer.cpp deleted file mode 100644 index bba59af99b4..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AC3AudioStreamFramer.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an AC3 audio elementary stream into frames -// Implementation - -#include "AC3AudioStreamFramer.hh" -#include "StreamParser.hh" -#include - -////////// AC3AudioStreamParser definition ////////// - -class AC3FrameParams { -public: - AC3FrameParams() : samplingFreq(0) {} - // 8-byte header at the start of each frame: - // u_int32_t hdr0, hdr1; - unsigned hdr0, hdr1; - - // parameters derived from the headers - unsigned kbps, samplingFreq, frameSize; - - void setParamsFromHeader(); -}; - -class AC3AudioStreamParser: public StreamParser { -public: - AC3AudioStreamParser(AC3AudioStreamFramer* usingSource, - FramedSource* inputSource); - virtual ~AC3AudioStreamParser(); - -public: - Boolean testStreamCode(unsigned char ourStreamCode, - unsigned char* ptr, unsigned size); - // returns True iff the initial stream code is ours - unsigned parseFrame(unsigned& numTruncatedBytes); - // returns the size of the frame that was acquired, or 0 if none was - - void registerReadInterest(unsigned char* to, unsigned maxSize); - - AC3FrameParams const& currentFrame() const { return fCurrentFrame; } - - Boolean haveParsedAFrame() const { return fHaveParsedAFrame; } - void readAndSaveAFrame(); - -private: - static void afterGettingSavedFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingSavedFrame1(unsigned frameSize); - static void onSavedFrameClosure(void* clientData); - void onSavedFrameClosure1(); - -private: - AC3AudioStreamFramer* fUsingSource; - unsigned char* fTo; - unsigned fMaxSize; - - Boolean fHaveParsedAFrame; - unsigned char* fSavedFrame; - unsigned fSavedFrameSize; - char fSavedFrameFlag; - - // Parameters of the most recently read frame: - AC3FrameParams fCurrentFrame; -}; - - -////////// AC3AudioStreamFramer implementation ////////// - -AC3AudioStreamFramer::AC3AudioStreamFramer(UsageEnvironment& env, - FramedSource* inputSource, - unsigned char streamCode) - : FramedFilter(env, inputSource), fOurStreamCode(streamCode) { - // Use the current wallclock time as the initial 'presentation time': - gettimeofday(&fNextFramePresentationTime, NULL); - - fParser = new AC3AudioStreamParser(this, inputSource); -} - -AC3AudioStreamFramer::~AC3AudioStreamFramer() { - delete fParser; -} - -AC3AudioStreamFramer* -AC3AudioStreamFramer::createNew(UsageEnvironment& env, - FramedSource* inputSource, - unsigned char streamCode) { - // Need to add source type checking here??? ##### - return new AC3AudioStreamFramer(env, inputSource, streamCode); -} - -unsigned AC3AudioStreamFramer::samplingRate() { - if (!fParser->haveParsedAFrame()) { - // Because we haven't yet parsed a frame, we don't yet know the input - // stream's sampling rate. So, we first need to read a frame - // (into a special buffer that we keep around for later use). - fParser->readAndSaveAFrame(); - } - - return fParser->currentFrame().samplingFreq; -} - -void AC3AudioStreamFramer::flushInput() { - fParser->flushInput(); -} - -void AC3AudioStreamFramer::doGetNextFrame() { - fParser->registerReadInterest(fTo, fMaxSize); - parseNextFrame(); -} - -#define MILLION 1000000 - -struct timeval AC3AudioStreamFramer::currentFramePlayTime() const { - AC3FrameParams const& fr = fParser->currentFrame(); - unsigned const numSamples = 1536; - unsigned const freq = fr.samplingFreq; - - // result is numSamples/freq - unsigned const uSeconds = (freq == 0) ? 0 - : ((numSamples*2*MILLION)/freq + 1)/2; // rounds to nearest integer - - struct timeval result; - result.tv_sec = uSeconds/MILLION; - result.tv_usec = uSeconds%MILLION; - return result; -} - -void AC3AudioStreamFramer -::handleNewData(void* clientData, unsigned char* ptr, unsigned size, - struct timeval /*presentationTime*/) { - AC3AudioStreamFramer* framer = (AC3AudioStreamFramer*)clientData; - framer->handleNewData(ptr, size); -} - -void AC3AudioStreamFramer -::handleNewData(unsigned char* ptr, unsigned size) { - if (!fParser->testStreamCode(fOurStreamCode, ptr, size)) { - // This block of data is not for us; try again: - parseNextFrame(); - return; - } - - // Now that we know that this data is for us, get the next frame: - parseNextFrame(); -} - -void AC3AudioStreamFramer::parseNextFrame() { - unsigned acquiredFrameSize = fParser->parseFrame(fNumTruncatedBytes); - if (acquiredFrameSize > 0) { - // We were able to acquire a frame from the input. - // It has already been copied to the reader's space. - fFrameSize = acquiredFrameSize; - - // Also set the presentation time, and increment it for next time, - // based on the length of this frame: - fPresentationTime = fNextFramePresentationTime; - - struct timeval framePlayTime = currentFramePlayTime(); - fDurationInMicroseconds = framePlayTime.tv_sec*MILLION + framePlayTime.tv_usec; - fNextFramePresentationTime.tv_usec += framePlayTime.tv_usec; - fNextFramePresentationTime.tv_sec - += framePlayTime.tv_sec + fNextFramePresentationTime.tv_usec/MILLION; - fNextFramePresentationTime.tv_usec %= MILLION; - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); - } else { - // We were unable to parse a complete frame from the input, because: - // - we had to read more data from the source stream, or - // - the source stream has ended. - } -} - - -////////// AC3AudioStreamParser implementation ////////// - -static int const kbpsTable[] = {32, 40, 48, 56, 64, 80, 96, 112, - 128, 160, 192, 224, 256, 320, 384, 448, - 512, 576, 640}; - -void AC3FrameParams::setParamsFromHeader() { - unsigned char byte4 = hdr1 >> 24; - - unsigned char kbpsIndex = (byte4&0x3E) >> 1; - if (kbpsIndex > 18) kbpsIndex = 18; - kbps = kbpsTable[kbpsIndex]; - - unsigned char samplingFreqIndex = (byte4&0xC0) >> 6; - switch (samplingFreqIndex) { - case 0: - samplingFreq = 48000; - frameSize = 4*kbps; - break; - case 1: - samplingFreq = 44100; - frameSize = 2*(320*kbps/147 + (byte4&1)); - break; - case 2: - case 3: // not legal? - samplingFreq = 32000; - frameSize = 6*kbps; - } -} - -AC3AudioStreamParser -::AC3AudioStreamParser(AC3AudioStreamFramer* usingSource, - FramedSource* inputSource) - : StreamParser(inputSource, FramedSource::handleClosure, usingSource, - &AC3AudioStreamFramer::handleNewData, usingSource), - fUsingSource(usingSource), fHaveParsedAFrame(False), - fSavedFrame(NULL), fSavedFrameSize(0) { -} - -AC3AudioStreamParser::~AC3AudioStreamParser() { -} - -void AC3AudioStreamParser::registerReadInterest(unsigned char* to, - unsigned maxSize) { - fTo = to; - fMaxSize = maxSize; -} - -Boolean AC3AudioStreamParser -::testStreamCode(unsigned char ourStreamCode, - unsigned char* ptr, unsigned size) { - if (size < 4) return False; // shouldn't happen - unsigned char streamCode = *ptr; - - if (streamCode == ourStreamCode) { - // Remove the first 4 bytes from the stream: - memmove(ptr, ptr + 4, size - 4); - totNumValidBytes() = totNumValidBytes() - 4; - - return True; - } else { - // Discard all of the data that was just read: - totNumValidBytes() = totNumValidBytes() - size; - - return False; - } -} - -unsigned AC3AudioStreamParser::parseFrame(unsigned& numTruncatedBytes) { - if (fSavedFrameSize > 0) { - // We've already read and parsed a frame. Use it instead: - memmove(fTo, fSavedFrame, fSavedFrameSize); - delete[] fSavedFrame; fSavedFrame = NULL; - unsigned frameSize = fSavedFrameSize; - fSavedFrameSize = 0; - return frameSize; - } - - try { - saveParserState(); - - // We expect an AC3 audio header (first 2 bytes == 0x0B77) at the start: - while (1) { - unsigned next4Bytes = test4Bytes(); - if (next4Bytes>>16 == 0x0B77) break; - skipBytes(1); - saveParserState(); - } - fCurrentFrame.hdr0 = get4Bytes(); - fCurrentFrame.hdr1 = test4Bytes(); - - fCurrentFrame.setParamsFromHeader(); - fHaveParsedAFrame = True; - - // Copy the frame to the requested destination: - unsigned frameSize = fCurrentFrame.frameSize; - if (frameSize > fMaxSize) { - numTruncatedBytes = frameSize - fMaxSize; - frameSize = fMaxSize; - } else { - numTruncatedBytes = 0; - } - - fTo[0] = fCurrentFrame.hdr0 >> 24; - fTo[1] = fCurrentFrame.hdr0 >> 16; - fTo[2] = fCurrentFrame.hdr0 >> 8; - fTo[3] = fCurrentFrame.hdr0; - getBytes(&fTo[4], frameSize-4); - skipBytes(numTruncatedBytes); - - return frameSize; - } catch (int /*e*/) { -#ifdef DEBUG - fUsingSource->envir() << "AC3AudioStreamParser::parseFrame() EXCEPTION (This is normal behavior - *not* an error)\n"; -#endif - return 0; // the parsing got interrupted - } -} - -void AC3AudioStreamParser::readAndSaveAFrame() { - unsigned const maxAC3FrameSize = 4000; - fSavedFrame = new unsigned char[maxAC3FrameSize]; - fSavedFrameSize = 0; - - fSavedFrameFlag = 0; - fUsingSource->getNextFrame(fSavedFrame, maxAC3FrameSize, - afterGettingSavedFrame, this, - onSavedFrameClosure, this); - fUsingSource->envir().taskScheduler().doEventLoop(&fSavedFrameFlag); -} - -void AC3AudioStreamParser -::afterGettingSavedFrame(void* clientData, unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval /*presentationTime*/, - unsigned /*durationInMicroseconds*/) { - AC3AudioStreamParser* parser = (AC3AudioStreamParser*)clientData; - parser->afterGettingSavedFrame1(frameSize); -} - -void AC3AudioStreamParser -::afterGettingSavedFrame1(unsigned frameSize) { - fSavedFrameSize = frameSize; - fSavedFrameFlag = ~0; -} - -void AC3AudioStreamParser::onSavedFrameClosure(void* clientData) { - AC3AudioStreamParser* parser = (AC3AudioStreamParser*)clientData; - parser->onSavedFrameClosure1(); -} - -void AC3AudioStreamParser::onSavedFrameClosure1() { - delete[] fSavedFrame; fSavedFrame = NULL; - fSavedFrameSize = 0; - fSavedFrameFlag = ~0; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/ADTSAudioFileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/ADTSAudioFileServerMediaSubsession.cpp deleted file mode 100644 index 33fe7d3c716..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/ADTSAudioFileServerMediaSubsession.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from an AAC audio file in ADTS format -// Implementation - -#include "ADTSAudioFileServerMediaSubsession.hh" -#include "ADTSAudioFileSource.hh" -#include "MPEG4GenericRTPSink.hh" - -ADTSAudioFileServerMediaSubsession* -ADTSAudioFileServerMediaSubsession::createNew(UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource) { - return new ADTSAudioFileServerMediaSubsession(env, fileName, reuseFirstSource); -} - -ADTSAudioFileServerMediaSubsession -::ADTSAudioFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource) - : FileServerMediaSubsession(env, fileName, reuseFirstSource) { -} - -ADTSAudioFileServerMediaSubsession -::~ADTSAudioFileServerMediaSubsession() { -} - -FramedSource* ADTSAudioFileServerMediaSubsession -::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) { - estBitrate = 96; // kbps, estimate - - return ADTSAudioFileSource::createNew(envir(), fFileName); -} - -RTPSink* ADTSAudioFileServerMediaSubsession -::createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource) { - ADTSAudioFileSource* adtsSource = (ADTSAudioFileSource*)inputSource; - return MPEG4GenericRTPSink::createNew(envir(), rtpGroupsock, - rtpPayloadTypeIfDynamic, - adtsSource->samplingFrequency(), - "audio", "AAC-hbr", adtsSource->configStr(), - adtsSource->numChannels()); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/ADTSAudioFileSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/ADTSAudioFileSource.cpp deleted file mode 100644 index 09ed86c808b..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/ADTSAudioFileSource.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A source object for AAC audio files in ADTS format -// Implementation - -#include "ADTSAudioFileSource.hh" -#include "InputFile.hh" -#include - -////////// ADTSAudioFileSource ////////// - -static unsigned const samplingFrequencyTable[16] = { - 96000, 88200, 64000, 48000, - 44100, 32000, 24000, 22050, - 16000, 12000, 11025, 8000, - 7350, 0, 0, 0 -}; - -ADTSAudioFileSource* -ADTSAudioFileSource::createNew(UsageEnvironment& env, char const* fileName) { - FILE* fid = NULL; - do { - fid = OpenInputFile(env, fileName); - if (fid == NULL) break; - - // Now, having opened the input file, read the fixed header of the first frame, - // to get the audio stream's parameters: - unsigned char fixedHeader[4]; // it's actually 3.5 bytes long - if (fread(fixedHeader, 1, sizeof fixedHeader, fid) < sizeof fixedHeader) break; - - // Check the 'syncword': - if (!(fixedHeader[0] == 0xFF && (fixedHeader[1]&0xF0) == 0xF0)) { - env.setResultMsg("Bad 'syncword' at start of ADTS file"); - break; - } - - // Get and check the 'profile': - u_int8_t profile = (fixedHeader[2]&0xC0)>>6; // 2 bits - if (profile == 3) { - env.setResultMsg("Bad (reserved) 'profile': 3 in first frame of ADTS file"); - break; - } - - // Get and check the 'sampling_frequency_index': - u_int8_t sampling_frequency_index = (fixedHeader[2]&0x3C)>>2; // 4 bits - if (samplingFrequencyTable[sampling_frequency_index] == 0) { - env.setResultMsg("Bad 'sampling_frequency_index' in first frame of ADTS file"); - break; - } - - // Get and check the 'channel_configuration': - u_int8_t channel_configuration - = ((fixedHeader[2]&0x01)<<2)|((fixedHeader[3]&0xC0)>>6); // 3 bits - - // If we get here, the frame header was OK. - // Reset the fid to the beginning of the file: - rewind(fid); -#ifdef DEBUG - fprintf(stderr, "Read first frame: profile %d, " - "sampling_frequency_index %d => samplingFrequency %d, " - "channel_configuration %d\n", - profile, - sampling_frequency_index, samplingFrequencyTable[sampling_frequency_index], - channel_configuration); -#endif - return new ADTSAudioFileSource(env, fid, profile, - sampling_frequency_index, channel_configuration); - } while (0); - - // An error occurred: - CloseInputFile(fid); - return NULL; -} - -ADTSAudioFileSource -::ADTSAudioFileSource(UsageEnvironment& env, FILE* fid, u_int8_t profile, - u_int8_t samplingFrequencyIndex, u_int8_t channelConfiguration) - : FramedFileSource(env, fid) { - fSamplingFrequency = samplingFrequencyTable[samplingFrequencyIndex]; - fNumChannels = channelConfiguration == 0 ? 2 : channelConfiguration; - fuSecsPerFrame - = (1024/*samples-per-frame*/*1000000) / fSamplingFrequency/*samples-per-second*/; - - // Construct the 'AudioSpecificConfig', and from it, the corresponding ASCII string: - unsigned char audioSpecificConfig[2]; - u_int8_t const audioObjectType = profile + 1; - audioSpecificConfig[0] = (audioObjectType<<3) | (samplingFrequencyIndex>>1); - audioSpecificConfig[1] = (samplingFrequencyIndex<<7) | (channelConfiguration<<3); - sprintf(fConfigStr, "%02X%02x", audioSpecificConfig[0], audioSpecificConfig[1]); -} - -ADTSAudioFileSource::~ADTSAudioFileSource() { - CloseInputFile(fFid); -} - -void ADTSAudioFileSource::doGetNextFrame() { - // Begin by reading the 7-byte fixed_variable headers: - unsigned char headers[7]; - if (fread(headers, 1, sizeof headers, fFid) < sizeof headers - || feof(fFid) || ferror(fFid)) { - // The input source has ended: - handleClosure(this); - return; - } - - // Extract important fields from the headers: - Boolean protection_absent = headers[1]&0x01; - u_int16_t frame_length - = ((headers[3]&0x03)<<11) | (headers[4]<<3) | ((headers[5]&0xE0)>>5); -#ifdef DEBUG - u_int16_t syncword = (headers[0]<<4) | (headers[1]>>4); - fprintf(stderr, "Read frame: syncword 0x%x, protection_absent %d, frame_length %d\n", syncword, protection_absent, frame_length); - if (syncword != 0xFFF) fprintf(stderr, "WARNING: Bad syncword!\n"); -#endif - unsigned numBytesToRead - = frame_length > sizeof headers ? frame_length - sizeof headers : 0; - - // If there's a 'crc_check' field, skip it: - if (!protection_absent) { - fseek(fFid, 2, SEEK_CUR); - numBytesToRead = numBytesToRead > 2 ? numBytesToRead - 2 : 0; - } - - // Next, read the raw frame data into the buffer provided: - if (numBytesToRead > fMaxSize) { - fNumTruncatedBytes = numBytesToRead - fMaxSize; - numBytesToRead = fMaxSize; - } - int numBytesRead = fread(fTo, 1, numBytesToRead, fFid); - if (numBytesRead < 0) numBytesRead = 0; - fFrameSize = numBytesRead; - fNumTruncatedBytes += numBytesToRead - numBytesRead; - - // Set the 'presentation time': - if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) { - // This is the first frame, so use the current time: - gettimeofday(&fPresentationTime, NULL); - } else { - // Increment by the play time of the previous frame: - unsigned uSeconds = fPresentationTime.tv_usec + fuSecsPerFrame; - fPresentationTime.tv_sec += uSeconds/1000000; - fPresentationTime.tv_usec = uSeconds%1000000; - } - - fDurationInMicroseconds = fuSecsPerFrame; - - // Switch to another task, and inform the reader that he has data: - nextTask() = envir().taskScheduler().scheduleDelayedTask(0, - (TaskFunc*)FramedSource::afterGetting, this); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileServerMediaSubsession.cpp deleted file mode 100644 index 55c6b0e1487..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileServerMediaSubsession.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from an AMR audio file. -// Implementation - -#include "AMRAudioFileServerMediaSubsession.hh" -#include "AMRAudioRTPSink.hh" -#include "AMRAudioFileSource.hh" - -AMRAudioFileServerMediaSubsession* -AMRAudioFileServerMediaSubsession::createNew(UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource) { - return new AMRAudioFileServerMediaSubsession(env, fileName, reuseFirstSource); -} - -AMRAudioFileServerMediaSubsession -::AMRAudioFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource) - : FileServerMediaSubsession(env, fileName, reuseFirstSource) { -} - -AMRAudioFileServerMediaSubsession -::~AMRAudioFileServerMediaSubsession() { -} - -FramedSource* AMRAudioFileServerMediaSubsession -::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) { - estBitrate = 10; // kbps, estimate - - return AMRAudioFileSource::createNew(envir(), fFileName); -} - -RTPSink* AMRAudioFileServerMediaSubsession -::createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource) { - AMRAudioFileSource* amrSource = (AMRAudioFileSource*)inputSource; - return AMRAudioRTPSink::createNew(envir(), rtpGroupsock, - rtpPayloadTypeIfDynamic, - amrSource->isWideband(), - amrSource->numChannels()); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileSink.cpp deleted file mode 100644 index b69145be500..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileSink.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// AMR Audio File sinks -// Implementation - -#include "AMRAudioFileSink.hh" -#include "AMRAudioSource.hh" -#include "OutputFile.hh" - -////////// AMRAudioFileSink ////////// - -AMRAudioFileSink -::AMRAudioFileSink(UsageEnvironment& env, FILE* fid, unsigned bufferSize, - char const* perFrameFileNamePrefix) - : FileSink(env, fid, bufferSize, perFrameFileNamePrefix), - fHaveWrittenHeader(False) { -} - -AMRAudioFileSink::~AMRAudioFileSink() { -} - -AMRAudioFileSink* -AMRAudioFileSink::createNew(UsageEnvironment& env, char const* fileName, - unsigned bufferSize, Boolean oneFilePerFrame) { - do { - FILE* fid; - char const* perFrameFileNamePrefix; - if (oneFilePerFrame) { - // Create the fid for each frame - fid = NULL; - perFrameFileNamePrefix = fileName; - } else { - // Normal case: create the fid once - fid = OpenOutputFile(env, fileName); - if (fid == NULL) break; - perFrameFileNamePrefix = NULL; - } - - return new AMRAudioFileSink(env, fid, bufferSize, perFrameFileNamePrefix); - } while (0); - - return NULL; -} - -Boolean AMRAudioFileSink::sourceIsCompatibleWithUs(MediaSource& source) { - // The input source must be a AMR Audio source: - return source.isAMRAudioSource(); -} - -void AMRAudioFileSink::afterGettingFrame1(unsigned frameSize, - struct timeval presentationTime) { - AMRAudioSource* source = (AMRAudioSource*)fSource; - - if (!fHaveWrittenHeader && fPerFrameFileNameBuffer == NULL) { - // Output the appropriate AMR header to the start of the file. - // This header is defined in RFC 3267, section 5. - // (However, we don't do this if we're creating one file per frame.) - char headerBuffer[100]; - sprintf(headerBuffer, "#!AMR%s%s\n", - source->isWideband() ? "-WB" : "", - source->numChannels() > 1 ? "_MC1.0" : ""); - unsigned headerLength = strlen(headerBuffer); - if (source->numChannels() > 1) { - // Also add a 32-bit channel description field: - headerBuffer[headerLength++] = 0; - headerBuffer[headerLength++] = 0; - headerBuffer[headerLength++] = 0; - headerBuffer[headerLength++] = source->numChannels(); - } - - addData((unsigned char*)headerBuffer, headerLength, presentationTime); - } - fHaveWrittenHeader = True; - - // Add the 1-byte header, before writing the file data proper: - // (Again, we don't do this if we're creating one file per frame.) - if (fPerFrameFileNameBuffer == NULL) { - u_int8_t frameHeader = source->lastFrameHeader(); - addData(&frameHeader, 1, presentationTime); - } - - // Call the parent class to complete the normal file write with the input data: - FileSink::afterGettingFrame1(frameSize, presentationTime); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileSource.cpp deleted file mode 100644 index 85cd5202897..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioFileSource.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A source object for AMR audio files (as defined in RFC 3267, section 5) -// Implementation - -#include "AMRAudioFileSource.hh" -#include "InputFile.hh" -#include "GroupsockHelper.hh" - -////////// AMRAudioFileSource ////////// - -AMRAudioFileSource* -AMRAudioFileSource::createNew(UsageEnvironment& env, char const* fileName) { - FILE* fid = NULL; - Boolean magicNumberOK = True; - do { - - fid = OpenInputFile(env, fileName); - if (fid == NULL) break; - - // Now, having opened the input file, read the first few bytes, to - // check the required 'magic number': - magicNumberOK = False; // until we learn otherwise - Boolean isWideband = False; // by default - unsigned numChannels = 1; // by default - char buf[100]; - // Start with the first 6 bytes (the first 5 of which must be "#!AMR"): - if (fread(buf, 1, 6, fid) < 6) break; - if (strncmp(buf, "#!AMR", 5) != 0) break; // bad magic # - unsigned bytesRead = 6; - - // The next bytes must be "\n", "-WB\n", "_MC1.0\n", or "-WB_MC1.0\n" - if (buf[5] == '-') { - // The next bytes must be "WB\n" or "WB_MC1.0\n" - if (fread(&buf[bytesRead], 1, 3, fid) < 3) break; - if (strncmp(&buf[bytesRead], "WB", 2) != 0) break; // bad magic # - isWideband = True; - bytesRead += 3; - } - if (buf[bytesRead-1] == '_') { - // The next bytes must be "MC1.0\n" - if (fread(&buf[bytesRead], 1, 6, fid) < 6) break; - if (strncmp(&buf[bytesRead], "MC1.0\n", 6) != 0) break; // bad magic # - bytesRead += 6; - - // The next 4 bytes contain the number of channels: - char channelDesc[4]; - if (fread(channelDesc, 1, 4, fid) < 4) break; - numChannels = channelDesc[3]&0xF; - } else if (buf[bytesRead-1] != '\n') { - break; // bad magic # - } - - // If we get here, the magic number was OK: - magicNumberOK = True; - -#ifdef DEBUG - fprintf(stderr, "isWideband: %d, numChannels: %d\n", - isWideband, numChannels); -#endif - return new AMRAudioFileSource(env, fid, isWideband, numChannels); - } while (0); - - // An error occurred: - CloseInputFile(fid); - if (!magicNumberOK) { - env.setResultMsg("Bad (or nonexistent) AMR file header"); - } - return NULL; -} - -AMRAudioFileSource -::AMRAudioFileSource(UsageEnvironment& env, FILE* fid, - Boolean isWideband, unsigned numChannels) - : AMRAudioSource(env, isWideband, numChannels), - fFid(fid) { -} - -AMRAudioFileSource::~AMRAudioFileSource() { - CloseInputFile(fFid); -} - -// The mapping from the "FT" field to frame size. -// Values of 65535 are invalid. -#define FT_INVALID 65535 -static unsigned short frameSize[16] = { - 12, 13, 15, 17, - 19, 20, 26, 31, - 5, FT_INVALID, FT_INVALID, FT_INVALID, - FT_INVALID, FT_INVALID, FT_INVALID, 0 -}; -static unsigned short frameSizeWideband[16] = { - 17, 23, 32, 36, - 40, 46, 50, 58, - 60, 5, FT_INVALID, FT_INVALID, - FT_INVALID, FT_INVALID, 0, 0 -}; - -void AMRAudioFileSource::doGetNextFrame() { - if (feof(fFid) || ferror(fFid)) { - handleClosure(this); - return; - } - - // Begin by reading the 1-byte frame header (and checking it for validity) - while (1) { - if (fread(&fLastFrameHeader, 1, 1, fFid) < 1) { - handleClosure(this); - return; - } - if ((fLastFrameHeader&0x83) != 0) { -#ifdef DEBUG - fprintf(stderr, "Invalid frame header 0x%02x (padding bits (0x83) are not zero)\n", fLastFrameHeader); -#endif - } else { - unsigned char ft = (fLastFrameHeader&0x78)>>3; - fFrameSize = fIsWideband ? frameSizeWideband[ft] : frameSize[ft]; - if (fFrameSize == FT_INVALID) { -#ifdef DEBUG - fprintf(stderr, "Invalid FT field %d (from frame header 0x%02x)\n", - ft, fLastFrameHeader); -#endif - } else { - // The frame header is OK -#ifdef DEBUG - fprintf(stderr, "Valid frame header 0x%02x -> ft %d -> frame size %d\n", fLastFrameHeader, ft, fFrameSize); -#endif - break; - } - } - } - - // Next, read the frame-block into the buffer provided: - fFrameSize *= fNumChannels; // because multiple channels make up a frame-block - if (fFrameSize > fMaxSize) { - fNumTruncatedBytes = fFrameSize - fMaxSize; - fFrameSize = fMaxSize; - } - fFrameSize = fread(fTo, 1, fFrameSize, fFid); - - // Set the 'presentation time': - if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) { - // This is the first frame, so use the current time: - gettimeofday(&fPresentationTime, NULL); - } else { - // Increment by the play time of the previous frame (20 ms) - unsigned uSeconds = fPresentationTime.tv_usec + 20000; - fPresentationTime.tv_sec += uSeconds/1000000; - fPresentationTime.tv_usec = uSeconds%1000000; - } - - fDurationInMicroseconds = 20000; // each frame is 20 ms - - // Switch to another task, and inform the reader that he has data: - nextTask() = envir().taskScheduler().scheduleDelayedTask(0, - (TaskFunc*)FramedSource::afterGetting, this); - } diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioRTPSink.cpp deleted file mode 100644 index 6f0eab20358..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioRTPSink.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for AMR audio (RFC 3267) -// Implementation - -// NOTE: At present, this is just a limited implementation, supporting: -// octet-alignment only; no interleaving; no frame CRC; no robust-sorting. - -#include "AMRAudioRTPSink.hh" -#include "AMRAudioSource.hh" - -AMRAudioRTPSink* -AMRAudioRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - Boolean sourceIsWideband, - unsigned numChannelsInSource) { - return new AMRAudioRTPSink(env, RTPgs, rtpPayloadFormat, - sourceIsWideband, numChannelsInSource); -} - -AMRAudioRTPSink -::AMRAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - Boolean sourceIsWideband, unsigned numChannelsInSource) - : AudioRTPSink(env, RTPgs, rtpPayloadFormat, - sourceIsWideband ? 16000 : 8000, - sourceIsWideband ? "AMR-WB": "AMR", - numChannelsInSource), - fSourceIsWideband(sourceIsWideband), fAuxSDPLine(NULL) { -} - -AMRAudioRTPSink::~AMRAudioRTPSink() { - delete[] fAuxSDPLine; -} - -Boolean AMRAudioRTPSink::sourceIsCompatibleWithUs(MediaSource& source) { - // Our source must be an AMR audio source: - if (!source.isAMRAudioSource()) return False; - - // Also, the source must be wideband iff we asked for this: - AMRAudioSource& amrSource = (AMRAudioSource&)source; - if ((amrSource.isWideband()^fSourceIsWideband) != 0) return False; - - // Also, the source must have the same number of channels that we - // specified. (It could, in principle, have more, but we don't - // support that.) - if (amrSource.numChannels() != numChannels()) return False; - - // Also, because in our current implementation we output only one - // frame in each RTP packet, this means that for multi-channel audio, - // each 'frame-block' will be split over multiple RTP packets, which - // may violate the spec. Warn about this: - if (amrSource.numChannels() > 1) { - envir() << "AMRAudioRTPSink: Warning: Input source has " << amrSource.numChannels() - << " audio channels. In the current implementation, the multi-frame frame-block will be split over multiple RTP packets\n"; - } - - return True; -} - -void AMRAudioRTPSink::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - // If this is the 1st frame in the 1st packet, set the RTP 'M' (marker) - // bit (because this is considered the start of a talk spurt): - if (isFirstPacket() && isFirstFrameInPacket()) { - setMarkerBit(); - } - - // If this is the first frame in the packet, set the 1-byte payload - // header (using CMR 15) - if (isFirstFrameInPacket()) { - u_int8_t payloadHeader = 0xF0; - setSpecialHeaderBytes(&payloadHeader, 1, 0); - } - - // Set the TOC field for the current frame, based on the "FT" and "Q" - // values from our source: - AMRAudioSource* amrSource = (AMRAudioSource*)fSource; - u_int8_t toc = amrSource->lastFrameHeader(); - // Clear the "F" bit, because we're the last frame in this packet: ##### - toc &=~ 0x80; - setSpecialHeaderBytes(&toc, 1, 1+numFramesUsedSoFar()); - - // Important: Also call our base class's doSpecialFrameHandling(), - // to set the packet's timestamp: - MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, - frameStart, numBytesInFrame, - frameTimestamp, - numRemainingBytes); -} - -Boolean AMRAudioRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - // For now, pack only one AMR frame into each outgoing RTP packet: ##### - return False; -} - -unsigned AMRAudioRTPSink::specialHeaderSize() const { - // For now, because we're packing only one frame per packet, - // there's just a 1-byte payload header, plus a 1-byte TOC ##### - return 2; -} - -char const* AMRAudioRTPSink::auxSDPLine() { - if (fAuxSDPLine == NULL) { - // Generate a "a=fmtp:" line with "octet-aligned=1" - // (That is the only non-default parameter.) - char buf[100]; - sprintf(buf, "a=fmtp:%d octet-align=1\r\n", rtpPayloadType()); - delete[] fAuxSDPLine; fAuxSDPLine = strDup(buf); - } - return fAuxSDPLine; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioRTPSource.cpp deleted file mode 100644 index 3cb449456a5..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioRTPSource.cpp +++ /dev/null @@ -1,741 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// AMR Audio RTP Sources (RFC 3267) -// Implementation - -#include "AMRAudioRTPSource.hh" -#include "MultiFramedRTPSource.hh" -#include "BitVector.hh" -#include -#include - -// This source is implemented internally by two separate sources: -// (i) a RTP source for the raw (and possibly interleaved) AMR frames, and -// (ii) a deinterleaving filter that reads from this. -// Define these two new classes here: - -class RawAMRRTPSource: public MultiFramedRTPSource { -public: - static RawAMRRTPSource* - createNew(UsageEnvironment& env, - Groupsock* RTPgs, unsigned char rtpPayloadFormat, - Boolean isWideband, Boolean isOctetAligned, - Boolean isInterleaved, Boolean CRCsArePresent); - - Boolean isWideband() const { return fIsWideband; } - unsigned char ILL() const { return fILL; } - unsigned char ILP() const { return fILP; } - unsigned TOCSize() const { return fTOCSize; } // total # of frames in the last pkt - unsigned char* TOC() const { return fTOC; } // FT+Q value for each TOC entry - unsigned& frameIndex() { return fFrameIndex; } // index of frame-block within pkt - -private: - RawAMRRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - Boolean isWideband, Boolean isOctetAligned, - Boolean isInterleaved, Boolean CRCsArePresent); - // called only by createNew() - - virtual ~RawAMRRTPSource(); - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; - - virtual Boolean hasBeenSynchronizedUsingRTCP(); - -private: - Boolean fIsWideband, fIsOctetAligned, fIsInterleaved, fCRCsArePresent; - unsigned char fILL, fILP; - unsigned fTOCSize; - unsigned char* fTOC; - unsigned fFrameIndex, fNumSuccessiveSyncedPackets; -}; - -class AMRDeinterleaver: public AMRAudioSource { -public: - static AMRDeinterleaver* - createNew(UsageEnvironment& env, - Boolean isWideband, unsigned numChannels, unsigned maxInterleaveGroupSize, - RawAMRRTPSource* inputSource); - -private: - AMRDeinterleaver(UsageEnvironment& env, - Boolean isWideband, unsigned numChannels, - unsigned maxInterleaveGroupSize, RawAMRRTPSource* inputSource); - // called only by "createNew()" - - virtual ~AMRDeinterleaver(); - - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, struct timeval presentationTime); - -private: - // Redefined virtual functions: - void doGetNextFrame(); - virtual void doStopGettingFrames(); - -private: - FramedSource* fInputSource; - class AMRDeinterleavingBuffer* fDeinterleavingBuffer; - Boolean fNeedAFrame; -}; - - -////////// AMRAudioRTPSource implementation ////////// - -#define MAX_NUM_CHANNELS 20 // far larger than ever expected... -#define MAX_INTERLEAVING_GROUP_SIZE 1000 // far larger than ever expected... - -AMRAudioSource* -AMRAudioRTPSource::createNew(UsageEnvironment& env, - Groupsock* RTPgs, - RTPSource*& resultRTPSource, - unsigned char rtpPayloadFormat, - Boolean isWideband, - unsigned numChannels, - Boolean isOctetAligned, - unsigned interleaving, - Boolean robustSortingOrder, - Boolean CRCsArePresent) { - // Perform sanity checks on the input parameters: - if (robustSortingOrder) { - env << "AMRAudioRTPSource::createNew(): 'Robust sorting order' was specified, but we don't yet support this!\n"; - return NULL; - } else if (numChannels > MAX_NUM_CHANNELS) { - env << "AMRAudioRTPSource::createNew(): The \"number of channels\" parameter (" - << numChannels << ") is much too large!\n"; - return NULL; - } else if (interleaving > MAX_INTERLEAVING_GROUP_SIZE) { - env << "AMRAudioRTPSource::createNew(): The \"interleaving\" parameter (" - << interleaving << ") is much too large!\n"; - return NULL; - } - - // 'Bandwidth-efficient mode' precludes some other options: - if (!isOctetAligned) { - if (interleaving > 0 || robustSortingOrder || CRCsArePresent) { - env << "AMRAudioRTPSource::createNew(): 'Bandwidth-efficient mode' was specified, along with interleaving, 'robust sorting order', and/or CRCs, so we assume 'octet-aligned mode' instead.\n"; - isOctetAligned = True; - } - } - - Boolean isInterleaved; - unsigned maxInterleaveGroupSize; // in frames (not frame-blocks) - if (interleaving > 0) { - isInterleaved = True; - maxInterleaveGroupSize = interleaving*numChannels; - } else { - isInterleaved = False; - maxInterleaveGroupSize = numChannels; - } - - RawAMRRTPSource* rawRTPSource; - resultRTPSource = rawRTPSource - = RawAMRRTPSource::createNew(env, RTPgs, rtpPayloadFormat, - isWideband, isOctetAligned, - isInterleaved, CRCsArePresent); - if (resultRTPSource == NULL) return NULL; - - AMRDeinterleaver* deinterleaver - = AMRDeinterleaver::createNew(env, isWideband, numChannels, - maxInterleaveGroupSize, rawRTPSource); - if (deinterleaver == NULL) { - Medium::close(resultRTPSource); - resultRTPSource = NULL; - } - - return deinterleaver; -} - - -////////// AMRBufferedPacket and AMRBufferedPacketFactory ////////// - -// A subclass of BufferedPacket, used to separate out AMR frames. - -class AMRBufferedPacket: public BufferedPacket { -public: - AMRBufferedPacket(RawAMRRTPSource& ourSource); - virtual ~AMRBufferedPacket(); - -private: // redefined virtual functions - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); -private: - RawAMRRTPSource& fOurSource; -}; - -class AMRBufferedPacketFactory: public BufferedPacketFactory { -private: // redefined virtual functions - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - - -///////// RawAMRRTPSource implementation //////// - -RawAMRRTPSource* -RawAMRRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - Boolean isWideband, Boolean isOctetAligned, - Boolean isInterleaved, Boolean CRCsArePresent) { - return new RawAMRRTPSource(env, RTPgs, rtpPayloadFormat, - isWideband, isOctetAligned, - isInterleaved, CRCsArePresent); -} - -RawAMRRTPSource -::RawAMRRTPSource(UsageEnvironment& env, - Groupsock* RTPgs, unsigned char rtpPayloadFormat, - Boolean isWideband, Boolean isOctetAligned, - Boolean isInterleaved, Boolean CRCsArePresent) - : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, - isWideband ? 16000 : 8000, - new AMRBufferedPacketFactory), - fIsWideband(isWideband), fIsOctetAligned(isOctetAligned), - fIsInterleaved(isInterleaved), fCRCsArePresent(CRCsArePresent), - fILL(0), fILP(0), fTOCSize(0), fTOC(NULL), fFrameIndex(0), - fNumSuccessiveSyncedPackets(0) { -} - -RawAMRRTPSource::~RawAMRRTPSource() { - delete[] fTOC; -} - -#define FT_SPEECH_LOST 14 -#define FT_NO_DATA 15 - -static void unpackBandwidthEfficientData(BufferedPacket* packet, - Boolean isWideband); // forward - -Boolean RawAMRRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - // If the data is 'bandwidth-efficient', first unpack it so that it's - // 'octet-aligned': - if (!fIsOctetAligned) unpackBandwidthEfficientData(packet, fIsWideband); - - unsigned char* headerStart = packet->data(); - unsigned packetSize = packet->dataSize(); - - // First, check whether this packet's RTP timestamp is synchronized: - if (RTPSource::hasBeenSynchronizedUsingRTCP()) { - ++fNumSuccessiveSyncedPackets; - } else { - fNumSuccessiveSyncedPackets = 0; - } - - // There's at least a 1-byte header, containing the CMR: - if (packetSize < 1) return False; - resultSpecialHeaderSize = 1; - - if (fIsInterleaved) { - // There's an extra byte, containing the interleave parameters: - if (packetSize < 2) return False; - - // Get the interleaving parameters, and check them for validity: - unsigned char const secondByte = headerStart[1]; - fILL = (secondByte&0xF0)>>4; - fILP = secondByte&0x0F; - if (fILP > fILL) return False; // invalid - ++resultSpecialHeaderSize; - } -#ifdef DEBUG - fprintf(stderr, "packetSize: %d, ILL: %d, ILP: %d\n", packetSize, fILL, fILP); -#endif - fFrameIndex = 0; // initially - - // Next, there's a "Payload Table of Contents" (one byte per entry): - unsigned numFramesPresent = 0, numNonEmptyFramesPresent = 0; - unsigned tocStartIndex = resultSpecialHeaderSize; - Boolean F; - do { - if (resultSpecialHeaderSize >= packetSize) return False; - unsigned char const tocByte = headerStart[resultSpecialHeaderSize++]; - F = (tocByte&0x80) != 0; - unsigned char const FT = (tocByte&0x78) >> 3; -#ifdef DEBUG - unsigned char Q = (tocByte&0x04)>>2; - fprintf(stderr, "\tTOC entry: F %d, FT %d, Q %d\n", F, FT, Q); -#endif - ++numFramesPresent; - if (FT != FT_SPEECH_LOST && FT != FT_NO_DATA) ++numNonEmptyFramesPresent; - } while (F); -#ifdef DEBUG - fprintf(stderr, "TOC contains %d entries (%d non-empty)\n", numFramesPresent, numNonEmptyFramesPresent); -#endif - - // Now that we know the size of the TOC, fill in our copy: - if (numFramesPresent > fTOCSize) { - delete[] fTOC; - fTOC = new unsigned char[numFramesPresent]; - } - fTOCSize = numFramesPresent; - for (unsigned i = 0; i < fTOCSize; ++i) { - unsigned char const tocByte = headerStart[tocStartIndex + i]; - fTOC[i] = tocByte&0x7C; // clear everything except the F and Q fields - } - - if (fCRCsArePresent) { - // 'numNonEmptyFramesPresent' CRC bytes will follow. - // Note: we currently don't check the CRCs for validity ##### - resultSpecialHeaderSize += numNonEmptyFramesPresent; -#ifdef DEBUG - fprintf(stderr, "Ignoring %d following CRC bytes\n", numNonEmptyFramesPresent); -#endif - if (resultSpecialHeaderSize > packetSize) return False; - } -#ifdef DEBUG - fprintf(stderr, "Total special header size: %d\n", resultSpecialHeaderSize); -#endif - - return True; -} - -char const* RawAMRRTPSource::MIMEtype() const { - return fIsWideband ? "audio/AMR-WB" : "audio/AMR-WB"; -} - -Boolean RawAMRRTPSource::hasBeenSynchronizedUsingRTCP() { - // Don't report ourselves as being synchronized until we've received - // at least a complete interleave cycle of synchronized packets. - // This ensures that the receiver is currently getting a frame from - // a packet that was synchronized. - if (fNumSuccessiveSyncedPackets > (unsigned)(fILL+1)) { - fNumSuccessiveSyncedPackets = fILL + 2; // prevents overflow - return True; - } - return False; -} - - -///// AMRBufferedPacket and AMRBufferedPacketFactory implementation - -AMRBufferedPacket::AMRBufferedPacket(RawAMRRTPSource& ourSource) - : fOurSource(ourSource) { -} - -AMRBufferedPacket::~AMRBufferedPacket() { -} - -// The mapping from the "FT" field to frame size. -// Values of 65535 are invalid. -#define FT_INVALID 65535 -static unsigned short frameBytesFromFT[16] = { - 12, 13, 15, 17, - 19, 20, 26, 31, - 5, FT_INVALID, FT_INVALID, FT_INVALID, - FT_INVALID, FT_INVALID, FT_INVALID, 0 -}; -static unsigned short frameBytesFromFTWideband[16] = { - 17, 23, 32, 36, - 40, 46, 50, 58, - 60, 5, FT_INVALID, FT_INVALID, - FT_INVALID, FT_INVALID, 0, 0 -}; - -unsigned AMRBufferedPacket:: - nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { - if (dataSize == 0) return 0; // sanity check - - // The size of the AMR frame is determined by the corresponding 'FT' value - // in the packet's Table of Contents. - unsigned const tocIndex = fOurSource.frameIndex(); - if (tocIndex >= fOurSource.TOCSize()) return 0; // sanity check - - unsigned char const tocByte = fOurSource.TOC()[tocIndex]; - unsigned char const FT = (tocByte&0x78) >> 3; - // ASSERT: FT < 16 - unsigned short frameSize - = fOurSource.isWideband() ? frameBytesFromFTWideband[FT] : frameBytesFromFT[FT]; - if (frameSize == FT_INVALID) { - // Strange TOC entry! - fOurSource.envir() << "AMRBufferedPacket::nextEnclosedFrameSize(): invalid FT: " << FT << "\n"; - frameSize = 0; // This probably messes up the rest of this packet, but... - } -#ifdef DEBUG - fprintf(stderr, "AMRBufferedPacket::nextEnclosedFrameSize(): frame #: %d, FT: %d, isWideband: %d => frameSize: %d (dataSize: %d)\n", tocIndex, FT, fOurSource.isWideband(), frameSize, dataSize); -#endif - ++fOurSource.frameIndex(); - - if (dataSize < frameSize) return 0; - return frameSize; -} - -BufferedPacket* AMRBufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* ourSource) { - return new AMRBufferedPacket((RawAMRRTPSource&)(*ourSource)); -} - -///////// AMRDeinterleavingBuffer ///////// -// (used to implement AMRDeinterleaver) - -#define AMR_MAX_FRAME_SIZE 60 - -class AMRDeinterleavingBuffer { -public: - AMRDeinterleavingBuffer(unsigned numChannels, unsigned maxInterleaveGroupSize); - virtual ~AMRDeinterleavingBuffer(); - - void deliverIncomingFrame(unsigned frameSize, RawAMRRTPSource* source, - struct timeval presentationTime); - Boolean retrieveFrame(unsigned char* to, unsigned maxSize, - unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes, - u_int8_t& resultFrameHeader, - struct timeval& resultPresentationTime); - - unsigned char* inputBuffer() { return fInputBuffer; } - unsigned inputBufferSize() const { return AMR_MAX_FRAME_SIZE; } - -private: - unsigned char* createNewBuffer(); - - class FrameDescriptor { - public: - FrameDescriptor(); - virtual ~FrameDescriptor(); - - unsigned frameSize; - unsigned char* frameData; - u_int8_t frameHeader; - struct timeval presentationTime; - }; - - unsigned fNumChannels, fMaxInterleaveGroupSize; - FrameDescriptor* fFrames[2]; - unsigned char fIncomingBankId; // toggles between 0 and 1 - unsigned char fIncomingBinMax; // in the incoming bank - unsigned char fOutgoingBinMax; // in the outgoing bank - unsigned char fNextOutgoingBin; - Boolean fHaveSeenPackets; - u_int16_t fLastPacketSeqNumForGroup; - unsigned char* fInputBuffer; - struct timeval fLastRetrievedPresentationTime; -}; - - -////////// AMRDeinterleaver implementation ///////// - -AMRDeinterleaver* AMRDeinterleaver -::createNew(UsageEnvironment& env, - Boolean isWideband, unsigned numChannels, unsigned maxInterleaveGroupSize, - RawAMRRTPSource* inputSource) { - return new AMRDeinterleaver(env, isWideband, numChannels, maxInterleaveGroupSize, - inputSource); -} - -AMRDeinterleaver::AMRDeinterleaver(UsageEnvironment& env, - Boolean isWideband, unsigned numChannels, - unsigned maxInterleaveGroupSize, - RawAMRRTPSource* inputSource) - : AMRAudioSource(env, isWideband, numChannels), - fInputSource(inputSource), fNeedAFrame(False) { - fDeinterleavingBuffer - = new AMRDeinterleavingBuffer(numChannels, maxInterleaveGroupSize); -} - -AMRDeinterleaver::~AMRDeinterleaver() { - delete fDeinterleavingBuffer; - Medium::close(fInputSource); -} - -static unsigned const uSecsPerFrame = 20000; // 20 ms - -void AMRDeinterleaver::doGetNextFrame() { - // First, try getting a frame from the deinterleaving buffer: - if (fDeinterleavingBuffer->retrieveFrame(fTo, fMaxSize, - fFrameSize, fNumTruncatedBytes, - fLastFrameHeader, fPresentationTime)) { - // Success! - fNeedAFrame = False; - - fDurationInMicroseconds = uSecsPerFrame; - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking - // infinite recursion - afterGetting(this); - return; - } - - // No luck, so ask our source for help: - fNeedAFrame = True; - if (!fInputSource->isCurrentlyAwaitingData()) { - fInputSource->getNextFrame(fDeinterleavingBuffer->inputBuffer(), - fDeinterleavingBuffer->inputBufferSize(), - afterGettingFrame, this, - FramedSource::handleClosure, this); - } -} - -void AMRDeinterleaver::doStopGettingFrames() { - fInputSource->stopGettingFrames(); -} - -void AMRDeinterleaver -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - AMRDeinterleaver* deinterleaver = (AMRDeinterleaver*)clientData; - deinterleaver->afterGettingFrame1(frameSize, presentationTime); -} - -void AMRDeinterleaver -::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime) { - RawAMRRTPSource* source = (RawAMRRTPSource*)fInputSource; - - // First, put the frame into our deinterleaving buffer: - fDeinterleavingBuffer->deliverIncomingFrame(frameSize, source, presentationTime); - - // Then, try delivering a frame to the client (if he wants one): - if (fNeedAFrame) doGetNextFrame(); -} - - -////////// AMRDeinterleavingBuffer implementation ///////// - -AMRDeinterleavingBuffer -::AMRDeinterleavingBuffer(unsigned numChannels, unsigned maxInterleaveGroupSize) - : fNumChannels(numChannels), fMaxInterleaveGroupSize(maxInterleaveGroupSize), - fIncomingBankId(0), fIncomingBinMax(0), - fOutgoingBinMax(0), fNextOutgoingBin(0), - fHaveSeenPackets(False) { - // Use two banks of descriptors - one for incoming, one for outgoing - fFrames[0] = new FrameDescriptor[fMaxInterleaveGroupSize]; - fFrames[1] = new FrameDescriptor[fMaxInterleaveGroupSize]; - fInputBuffer = createNewBuffer(); -} - -AMRDeinterleavingBuffer::~AMRDeinterleavingBuffer() { - delete[] fInputBuffer; - delete[] fFrames[0]; delete[] fFrames[1]; -} - -void AMRDeinterleavingBuffer -::deliverIncomingFrame(unsigned frameSize, RawAMRRTPSource* source, - struct timeval presentationTime) { - unsigned char const ILL = source->ILL(); - unsigned char const ILP = source->ILP(); - unsigned frameIndex = source->frameIndex(); - unsigned short packetSeqNum = source->curPacketRTPSeqNum(); - - // First perform a sanity check on the parameters: - // (This is overkill, as the source should have already done this.) - if (ILP > ILL || frameIndex == 0) { -#ifdef DEBUG - fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame() param sanity check failed (%d,%d,%d,%d)\n", frameSize, ILL, ILP, frameIndex); -#endif - exit(1); - } - - --frameIndex; // because it was incremented by the source when this frame was read - u_int8_t frameHeader; - if (frameIndex >= source->TOCSize()) { // sanity check - frameHeader = FT_NO_DATA<<3; - } else { - frameHeader = source->TOC()[frameIndex]; - } - - unsigned frameBlockIndex = frameIndex/fNumChannels; - unsigned frameWithinFrameBlock = frameIndex%fNumChannels; - - // The input "presentationTime" was that of the first frame-block in this - // packet. Update it for the current frame: - unsigned uSecIncrement = frameBlockIndex*(ILL+1)*uSecsPerFrame; - presentationTime.tv_usec += uSecIncrement; - presentationTime.tv_sec += presentationTime.tv_usec/1000000; - presentationTime.tv_usec = presentationTime.tv_usec%1000000; - - // Next, check whether this packet is part of a new interleave group - if (!fHaveSeenPackets - || seqNumLT(fLastPacketSeqNumForGroup, packetSeqNum + frameBlockIndex)) { - // We've moved to a new interleave group -#ifdef DEBUG - fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame(): new interleave group\n"); -#endif - fHaveSeenPackets = True; - fLastPacketSeqNumForGroup = packetSeqNum + ILL - ILP; - - // Switch the incoming and outgoing banks: - fIncomingBankId ^= 1; - unsigned char tmp = fIncomingBinMax; - fIncomingBinMax = fOutgoingBinMax; - fOutgoingBinMax = tmp; - fNextOutgoingBin = 0; - } - - // Now move the incoming frame into the appropriate bin: - unsigned const binNumber - = ((ILP + frameBlockIndex*(ILL+1))*fNumChannels + frameWithinFrameBlock) - % fMaxInterleaveGroupSize; // the % is for sanity -#ifdef DEBUG - fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame(): frameIndex %d (%d,%d) put in bank %d, bin %d (%d): size %d, header 0x%02x, presentationTime %lu.%06ld\n", frameIndex, frameBlockIndex, frameWithinFrameBlock, fIncomingBankId, binNumber, fMaxInterleaveGroupSize, frameSize, frameHeader, presentationTime.tv_sec, presentationTime.tv_usec); -#endif - FrameDescriptor& inBin = fFrames[fIncomingBankId][binNumber]; - unsigned char* curBuffer = inBin.frameData; - inBin.frameData = fInputBuffer; - inBin.frameSize = frameSize; - inBin.frameHeader = frameHeader; - inBin.presentationTime = presentationTime; - - if (curBuffer == NULL) curBuffer = createNewBuffer(); - fInputBuffer = curBuffer; - - if (binNumber >= fIncomingBinMax) { - fIncomingBinMax = binNumber + 1; - } -} - -Boolean AMRDeinterleavingBuffer -::retrieveFrame(unsigned char* to, unsigned maxSize, - unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes, - u_int8_t& resultFrameHeader, - struct timeval& resultPresentationTime) { - if (fNextOutgoingBin >= fOutgoingBinMax) return False; // none left - - FrameDescriptor& outBin = fFrames[fIncomingBankId^1][fNextOutgoingBin]; - unsigned char* fromPtr = outBin.frameData; - unsigned char fromSize = outBin.frameSize; - outBin.frameSize = 0; // for the next time this bin is used - - // Check whether this frame is missing; if so, return a FT_NO_DATA frame: - if (fromSize == 0) { - resultFrameHeader = FT_NO_DATA<<3; - - // Compute this erasure frame's presentation time via extrapolation: - resultPresentationTime = fLastRetrievedPresentationTime; - resultPresentationTime.tv_usec += uSecsPerFrame; - if (resultPresentationTime.tv_usec >= 1000000) { - ++resultPresentationTime.tv_sec; - resultPresentationTime.tv_usec -= 1000000; - } - } else { - // Normal case - a frame exists: - resultFrameHeader = outBin.frameHeader; - resultPresentationTime = outBin.presentationTime; - } - - fLastRetrievedPresentationTime = resultPresentationTime; - - if (fromSize > maxSize) { - resultNumTruncatedBytes = fromSize - maxSize; - resultFrameSize = maxSize; - } else { - resultNumTruncatedBytes = 0; - resultFrameSize = fromSize; - } - memmove(to, fromPtr, resultFrameSize); -#ifdef DEBUG - fprintf(stderr, "AMRDeinterleavingBuffer::retrieveFrame(): from bank %d, bin %d: size %d, header 0x%02x, presentationTime %lu.%06ld\n", fIncomingBankId^1, fNextOutgoingBin, resultFrameSize, resultFrameHeader, resultPresentationTime.tv_sec, resultPresentationTime.tv_usec); -#endif - - ++fNextOutgoingBin; - return True; -} - -unsigned char* AMRDeinterleavingBuffer::createNewBuffer() { - return new unsigned char[inputBufferSize()]; -} - -AMRDeinterleavingBuffer::FrameDescriptor::FrameDescriptor() - : frameSize(0), frameData(NULL) { -} - -AMRDeinterleavingBuffer::FrameDescriptor::~FrameDescriptor() { - delete[] frameData; -} - -// Unpack bandwidth-aligned data to octet-aligned: -static unsigned short frameBitsFromFT[16] = { - 95, 103, 118, 134, - 148, 159, 204, 244, - 39, 0, 0, 0, - 0, 0, 0, 0 -}; -static unsigned short frameBitsFromFTWideband[16] = { - 132, 177, 253, 285, - 317, 365, 397, 461, - 477, 40, 0, 0, - 0, 0, 0, 0 -}; - -static void unpackBandwidthEfficientData(BufferedPacket* packet, - Boolean isWideband) { -#ifdef DEBUG - fprintf(stderr, "Unpacking 'bandwidth-efficient' payload (%d bytes):\n", packet->dataSize()); - for (unsigned j = 0; j < packet->dataSize(); ++j) { - fprintf(stderr, "%02x:", (packet->data())[j]); - } - fprintf(stderr, "\n"); -#endif - BitVector fromBV(packet->data(), 0, 8*packet->dataSize()); - - unsigned const toBufferSize = 2*packet->dataSize(); // conservatively large - unsigned char* toBuffer = new unsigned char[toBufferSize]; - unsigned toCount = 0; - - // Begin with the payload header: - unsigned CMR = fromBV.getBits(4); - toBuffer[toCount++] = CMR << 4; - - // Then, run through and unpack the TOC entries: - while (1) { - unsigned toc = fromBV.getBits(6); - toBuffer[toCount++] = toc << 2; - - if ((toc&0x20) == 0) break; // the F bit is 0 - } - - // Then, using the TOC data, unpack each frame payload: - unsigned const tocSize = toCount - 1; - for (unsigned i = 1; i <= tocSize; ++i) { - unsigned char tocByte = toBuffer[i]; - unsigned char const FT = (tocByte&0x78) >> 3; - unsigned short frameSizeBits - = isWideband ? frameBitsFromFTWideband[FT] : frameBitsFromFT[FT]; - unsigned short frameSizeBytes = (frameSizeBits+7)/8; - - shiftBits(&toBuffer[toCount], 0, // to - packet->data(), fromBV.curBitIndex(), // from - frameSizeBits // num bits - ); -#ifdef DEBUG - if (frameSizeBits > fromBV.numBitsRemaining()) { - fprintf(stderr, "\tWarning: Unpacking frame %d of %d: want %d bits, but only %d are available!\n", i, tocSize, frameSizeBits, fromBV.numBitsRemaining()); - } -#endif - fromBV.skipBits(frameSizeBits); - toCount += frameSizeBytes; - } - -#ifdef DEBUG - if (fromBV.numBitsRemaining() > 7) { - fprintf(stderr, "\tWarning: %d bits remain unused!\n", fromBV.numBitsRemaining()); - } -#endif - - // Finally, replace the current packet data with the unpacked data: - packet->removePadding(packet->dataSize()); // throws away current packet data - packet->appendData(toBuffer, toCount); - delete[] toBuffer; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioSource.cpp deleted file mode 100644 index c033a8fd707..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AMRAudioSource.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A source object for AMR audio sources -// Implementation - -#include "AMRAudioSource.hh" - -AMRAudioSource::AMRAudioSource(UsageEnvironment& env, - Boolean isWideband, unsigned numChannels) - : FramedSource(env), - fIsWideband(isWideband), fNumChannels(numChannels), fLastFrameHeader(0) { -} - -AMRAudioSource::~AMRAudioSource() { -} - -Boolean AMRAudioSource::isAMRAudioSource() const { - return True; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AVIFileSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AVIFileSink.cpp deleted file mode 100644 index 8459b97e276..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AVIFileSink.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A sink that generates an AVI file from a composite media session -// Implementation - -#include "AVIFileSink.hh" -#include "OutputFile.hh" -#include "GroupsockHelper.hh" - -#define fourChar(x,y,z,w) ( ((w)<<24)|((z)<<16)|((y)<<8)|(x) )/*little-endian*/ - -////////// AVISubsessionIOState /////////// -// A structure used to represent the I/O state of each input 'subsession': - -class SubsessionBuffer { -public: - SubsessionBuffer(unsigned bufferSize) - : fBufferSize(bufferSize) { - reset(); - fData = new unsigned char[bufferSize]; - } - virtual ~SubsessionBuffer() { delete[] fData; } - void reset() { fBytesInUse = 0; } - void addBytes(unsigned numBytes) { fBytesInUse += numBytes; } - - unsigned char* dataStart() { return &fData[0]; } - unsigned char* dataEnd() { return &fData[fBytesInUse]; } - unsigned bytesInUse() const { return fBytesInUse; } - unsigned bytesAvailable() const { return fBufferSize - fBytesInUse; } - - void setPresentationTime(struct timeval const& presentationTime) { - fPresentationTime = presentationTime; - } - struct timeval const& presentationTime() const {return fPresentationTime;} - -private: - unsigned fBufferSize; - struct timeval fPresentationTime; - unsigned char* fData; - unsigned fBytesInUse; -}; - -class AVISubsessionIOState { -public: - AVISubsessionIOState(AVIFileSink& sink, MediaSubsession& subsession); - virtual ~AVISubsessionIOState(); - - void setAVIstate(unsigned subsessionIndex); - void setFinalAVIstate(); - - void afterGettingFrame(unsigned packetDataSize, - struct timeval presentationTime); - void onSourceClosure(); - - UsageEnvironment& envir() const { return fOurSink.envir(); } - -public: - SubsessionBuffer *fBuffer, *fPrevBuffer; - AVIFileSink& fOurSink; - MediaSubsession& fOurSubsession; - - unsigned short fLastPacketRTPSeqNum; - Boolean fOurSourceIsActive; - struct timeval fPrevPresentationTime; - unsigned fMaxBytesPerSecond; - Boolean fIsVideo, fIsAudio, fIsByteSwappedAudio; - unsigned fAVISubsessionTag; - unsigned fAVICodecHandlerType; - unsigned fAVISamplingFrequency; // for audio - u_int16_t fWAVCodecTag; // for audio - unsigned fAVIScale; - unsigned fAVIRate; - unsigned fAVISize; - unsigned fNumFrames; - unsigned fSTRHFrameCountPosition; - -private: - void useFrame(SubsessionBuffer& buffer); -}; - - -////////// AVIFileSink implementation ////////// - -AVIFileSink::AVIFileSink(UsageEnvironment& env, - MediaSession& inputSession, - FILE* outFid, - unsigned bufferSize, - unsigned short movieWidth, unsigned short movieHeight, - unsigned movieFPS, Boolean packetLossCompensate) - : Medium(env), fInputSession(inputSession), fOutFid(outFid), - fBufferSize(bufferSize), fPacketLossCompensate(packetLossCompensate), - fAreCurrentlyBeingPlayed(False), fNumSubsessions(0), fNumBytesWritten(0), - fHaveCompletedOutputFile(False), - fMovieWidth(movieWidth), fMovieHeight(movieHeight), fMovieFPS(movieFPS) { - // Set up I/O state for each input subsession: - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - // Ignore subsessions without a data source: - FramedSource* subsessionSource = subsession->readSource(); - if (subsessionSource == NULL) continue; - - // If "subsession's" SDP description specified screen dimension - // or frame rate parameters, then use these. - if (subsession->videoWidth() != 0) { - fMovieWidth = subsession->videoWidth(); - } - if (subsession->videoHeight() != 0) { - fMovieHeight = subsession->videoHeight(); - } - if (subsession->videoFPS() != 0) { - fMovieFPS = subsession->videoFPS(); - } - - AVISubsessionIOState* ioState - = new AVISubsessionIOState(*this, *subsession); - subsession->miscPtr = (void*)ioState; - - // Also set a 'BYE' handler for this subsession's RTCP instance: - if (subsession->rtcpInstance() != NULL) { - subsession->rtcpInstance()->setByeHandler(onRTCPBye, ioState); - } - - ++fNumSubsessions; - } - - // Begin by writing an AVI header: - addFileHeader_AVI(); -} - -AVIFileSink::~AVIFileSink() { - completeOutputFile(); - - // Then, delete each active "AVISubsessionIOState": - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - AVISubsessionIOState* ioState - = (AVISubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - delete ioState; - } -} - -AVIFileSink* AVIFileSink -::createNew(UsageEnvironment& env, MediaSession& inputSession, - char const* outputFileName, - unsigned bufferSize, - unsigned short movieWidth, unsigned short movieHeight, - unsigned movieFPS, Boolean packetLossCompensate) { - do { - FILE* fid = OpenOutputFile(env, outputFileName); - if (fid == NULL) break; - - return new AVIFileSink(env, inputSession, fid, bufferSize, - movieWidth, movieHeight, movieFPS, - packetLossCompensate); - } while (0); - - return NULL; -} - -Boolean AVIFileSink::startPlaying(afterPlayingFunc* afterFunc, - void* afterClientData) { - // Make sure we're not already being played: - if (fAreCurrentlyBeingPlayed) { - envir().setResultMsg("This sink has already been played"); - return False; - } - - fAreCurrentlyBeingPlayed = True; - fAfterFunc = afterFunc; - fAfterClientData = afterClientData; - - return continuePlaying(); -} - -Boolean AVIFileSink::continuePlaying() { - // Run through each of our input session's 'subsessions', - // asking for a frame from each one: - Boolean haveActiveSubsessions = False; - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - FramedSource* subsessionSource = subsession->readSource(); - if (subsessionSource == NULL) continue; - - if (subsessionSource->isCurrentlyAwaitingData()) continue; - - AVISubsessionIOState* ioState - = (AVISubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - haveActiveSubsessions = True; - unsigned char* toPtr = ioState->fBuffer->dataEnd(); - unsigned toSize = ioState->fBuffer->bytesAvailable(); - subsessionSource->getNextFrame(toPtr, toSize, - afterGettingFrame, ioState, - onSourceClosure, ioState); - } - if (!haveActiveSubsessions) { - envir().setResultMsg("No subsessions are currently active"); - return False; - } - - return True; -} - -void AVIFileSink -::afterGettingFrame(void* clientData, unsigned packetDataSize, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - AVISubsessionIOState* ioState = (AVISubsessionIOState*)clientData; - ioState->afterGettingFrame(packetDataSize, presentationTime); -} - -void AVIFileSink::onSourceClosure(void* clientData) { - AVISubsessionIOState* ioState = (AVISubsessionIOState*)clientData; - ioState->onSourceClosure(); -} - -void AVIFileSink::onSourceClosure1() { - // Check whether *all* of the subsession sources have closed. - // If not, do nothing for now: - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - AVISubsessionIOState* ioState - = (AVISubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - if (ioState->fOurSourceIsActive) return; // this source hasn't closed - } - - completeOutputFile(); - - // Call our specified 'after' function: - if (fAfterFunc != NULL) { - (*fAfterFunc)(fAfterClientData); - } -} - -void AVIFileSink::onRTCPBye(void* clientData) { - AVISubsessionIOState* ioState = (AVISubsessionIOState*)clientData; - - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - unsigned secsDiff - = timeNow.tv_sec - ioState->fOurSink.fStartTime.tv_sec; - - MediaSubsession& subsession = ioState->fOurSubsession; - ioState->envir() << "Received RTCP \"BYE\" on \"" - << subsession.mediumName() - << "/" << subsession.codecName() - << "\" subsession (after " - << secsDiff << " seconds)\n"; - - // Handle the reception of a RTCP "BYE" as if the source had closed: - ioState->onSourceClosure(); -} - -void AVIFileSink::completeOutputFile() { - if (fHaveCompletedOutputFile || fOutFid == NULL) return; - - // Update various AVI 'size' fields to take account of the codec data that - // we've now written to the file: - unsigned maxBytesPerSecond = 0; - unsigned numVideoFrames = 0; - unsigned numAudioFrames = 0; - - //// Subsession-specific fields: - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - AVISubsessionIOState* ioState - = (AVISubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - maxBytesPerSecond += ioState->fMaxBytesPerSecond; - - setWord(ioState->fSTRHFrameCountPosition, ioState->fNumFrames); - if (ioState->fIsVideo) numVideoFrames = ioState->fNumFrames; - else if (ioState->fIsAudio) numAudioFrames = ioState->fNumFrames; - } - - //// Global fields: - fRIFFSizeValue += fNumBytesWritten; - setWord(fRIFFSizePosition, fRIFFSizeValue); - - setWord(fAVIHMaxBytesPerSecondPosition, maxBytesPerSecond); - setWord(fAVIHFrameCountPosition, - numVideoFrames > 0 ? numVideoFrames : numAudioFrames); - - fMoviSizeValue += fNumBytesWritten; - setWord(fMoviSizePosition, fMoviSizeValue); - - // We're done: - fHaveCompletedOutputFile = True; -} - - -////////// AVISubsessionIOState implementation /////////// - -AVISubsessionIOState::AVISubsessionIOState(AVIFileSink& sink, - MediaSubsession& subsession) - : fOurSink(sink), fOurSubsession(subsession), - fMaxBytesPerSecond(0), fNumFrames(0) { - fBuffer = new SubsessionBuffer(fOurSink.fBufferSize); - fPrevBuffer = sink.fPacketLossCompensate - ? new SubsessionBuffer(fOurSink.fBufferSize) : NULL; - - FramedSource* subsessionSource = subsession.readSource(); - fOurSourceIsActive = subsessionSource != NULL; - - fPrevPresentationTime.tv_sec = 0; - fPrevPresentationTime.tv_usec = 0; -} - -AVISubsessionIOState::~AVISubsessionIOState() { - delete fBuffer; delete fPrevBuffer; -} - -void AVISubsessionIOState::setAVIstate(unsigned subsessionIndex) { - fIsVideo = strcmp(fOurSubsession.mediumName(), "video") == 0; - fIsAudio = strcmp(fOurSubsession.mediumName(), "audio") == 0; - - if (fIsVideo) { - fAVISubsessionTag - = fourChar('0'+subsessionIndex/10,'0'+subsessionIndex%10,'d','c'); - if (strcmp(fOurSubsession.codecName(), "JPEG") == 0) { - fAVICodecHandlerType = fourChar('m','j','p','g'); - } else if (strcmp(fOurSubsession.codecName(), "MP4V-ES") == 0) { - fAVICodecHandlerType = fourChar('D','I','V','X'); - } else if (strcmp(fOurSubsession.codecName(), "MPV") == 0) { - fAVICodecHandlerType = fourChar('m','p','g','1'); // what about MPEG-2? - } else if (strcmp(fOurSubsession.codecName(), "H263-1998") == 0 || - strcmp(fOurSubsession.codecName(), "H263-2000") == 0) { - fAVICodecHandlerType = fourChar('H','2','6','3'); - } else if (strcmp(fOurSubsession.codecName(), "H264") == 0) { - fAVICodecHandlerType = fourChar('H','2','6','4'); - } else { - fAVICodecHandlerType = fourChar('?','?','?','?'); - } - fAVIScale = 1; // ??? ##### - fAVIRate = fOurSink.fMovieFPS; // ??? ##### - fAVISize = fOurSink.fMovieWidth*fOurSink.fMovieHeight*3; // ??? ##### - } else if (fIsAudio) { - fIsByteSwappedAudio = False; // by default - fAVISubsessionTag - = fourChar('0'+subsessionIndex/10,'0'+subsessionIndex%10,'w','b'); - fAVICodecHandlerType = 1; // ??? #### - unsigned numChannels = fOurSubsession.numChannels(); - fAVISamplingFrequency = fOurSubsession.rtpTimestampFrequency(); // default - if (strcmp(fOurSubsession.codecName(), "L16") == 0) { - fIsByteSwappedAudio = True; // need to byte-swap data before writing it - fWAVCodecTag = 0x0001; - fAVIScale = fAVISize = 2*numChannels; // 2 bytes/sample - fAVIRate = fAVISize*fAVISamplingFrequency; - } else if (strcmp(fOurSubsession.codecName(), "L8") == 0) { - fWAVCodecTag = 0x0001; - fAVIScale = fAVISize = numChannels; // 1 byte/sample - fAVIRate = fAVISize*fAVISamplingFrequency; - } else if (strcmp(fOurSubsession.codecName(), "PCMA") == 0) { - fWAVCodecTag = 0x0006; - fAVIScale = fAVISize = numChannels; // 1 byte/sample - fAVIRate = fAVISize*fAVISamplingFrequency; - } else if (strcmp(fOurSubsession.codecName(), "PCMU") == 0) { - fWAVCodecTag = 0x0007; - fAVIScale = fAVISize = numChannels; // 1 byte/sample - fAVIRate = fAVISize*fAVISamplingFrequency; - } else if (strcmp(fOurSubsession.codecName(), "MPA") == 0) { - fWAVCodecTag = 0x0050; - fAVIScale = fAVISize = 1; - fAVIRate = 0; // ??? ##### - } else { - fWAVCodecTag = 0x0001; // ??? ##### - fAVIScale = fAVISize = 1; - fAVIRate = 0; // ??? ##### - } - } else { // unknown medium - fAVISubsessionTag - = fourChar('0'+subsessionIndex/10,'0'+subsessionIndex%10,'?','?'); - fAVICodecHandlerType = 0; - fAVIScale = fAVISize = 1; - fAVIRate = 0; // ??? ##### - } -} - -void AVISubsessionIOState::afterGettingFrame(unsigned packetDataSize, - struct timeval presentationTime) { - // Begin by checking whether there was a gap in the RTP stream. - // If so, try to compensate for this (if desired): - unsigned short rtpSeqNum - = fOurSubsession.rtpSource()->curPacketRTPSeqNum(); - if (fOurSink.fPacketLossCompensate && fPrevBuffer->bytesInUse() > 0) { - short seqNumGap = rtpSeqNum - fLastPacketRTPSeqNum; - for (short i = 1; i < seqNumGap; ++i) { - // Insert a copy of the previous frame, to compensate for the loss: - useFrame(*fPrevBuffer); - } - } - fLastPacketRTPSeqNum = rtpSeqNum; - - // Now, continue working with the frame that we just got - if (fBuffer->bytesInUse() == 0) { - fBuffer->setPresentationTime(presentationTime); - } - fBuffer->addBytes(packetDataSize); - - useFrame(*fBuffer); - if (fOurSink.fPacketLossCompensate) { - // Save this frame, in case we need it for recovery: - SubsessionBuffer* tmp = fPrevBuffer; // assert: != NULL - fPrevBuffer = fBuffer; - fBuffer = tmp; - } - fBuffer->reset(); // for the next input - - // Now, try getting more frames: - fOurSink.continuePlaying(); -} - -void AVISubsessionIOState::useFrame(SubsessionBuffer& buffer) { - unsigned char* const frameSource = buffer.dataStart(); - unsigned const frameSize = buffer.bytesInUse(); - struct timeval const& presentationTime = buffer.presentationTime(); - if (fPrevPresentationTime.tv_usec != 0||fPrevPresentationTime.tv_sec != 0) { - int uSecondsDiff - = (presentationTime.tv_sec - fPrevPresentationTime.tv_sec)*1000000 - + (presentationTime.tv_usec - fPrevPresentationTime.tv_usec); - if (uSecondsDiff > 0) { - unsigned bytesPerSecond = (unsigned)((frameSize*1000000.0)/uSecondsDiff); - if (bytesPerSecond > fMaxBytesPerSecond) { - fMaxBytesPerSecond = bytesPerSecond; - } - } - } - fPrevPresentationTime = presentationTime; - - if (fIsByteSwappedAudio) { - // We need to swap the 16-bit audio samples from big-endian - // to little-endian order, before writing them to a file: - for (unsigned i = 0; i < frameSize; i += 2) { - unsigned char tmp = frameSource[i]; - frameSource[i] = frameSource[i+1]; - frameSource[i+1] = tmp; - } - } - - // Write the data into the file: - fOurSink.fNumBytesWritten += fOurSink.addWord(fAVISubsessionTag); - fOurSink.fNumBytesWritten += fOurSink.addWord(frameSize); - fwrite(frameSource, 1, frameSize, fOurSink.fOutFid); - fOurSink.fNumBytesWritten += frameSize; - // Pad to an even length: - if (frameSize%2 != 0) fOurSink.fNumBytesWritten += fOurSink.addByte(0); - - ++fNumFrames; -} - -void AVISubsessionIOState::onSourceClosure() { - fOurSourceIsActive = False; - fOurSink.onSourceClosure1(); -} - - -////////// AVI-specific implementation ////////// - -unsigned AVIFileSink::addWord(unsigned word) { - // Add "word" to the file in little-endian order: - addByte(word); addByte(word>>8); - addByte(word>>16); addByte(word>>24); - - return 4; -} - -unsigned AVIFileSink::addHalfWord(unsigned short halfWord) { - // Add "halfWord" to the file in little-endian order: - addByte((unsigned char)halfWord); addByte((unsigned char)(halfWord>>8)); - - return 2; -} - -unsigned AVIFileSink::addZeroWords(unsigned numWords) { - for (unsigned i = 0; i < numWords; ++i) { - addWord(0); - } - - return numWords*4; -} - -unsigned AVIFileSink::add4ByteString(char const* str) { - addByte(str[0]); addByte(str[1]); addByte(str[2]); - addByte(str[3] == '\0' ? ' ' : str[3]); // e.g., for "AVI " - - return 4; -} - -void AVIFileSink::setWord(unsigned filePosn, unsigned size) { - do { - if (fseek(fOutFid, filePosn, SEEK_SET) < 0) break; - addWord(size); - if (fseek(fOutFid, 0, SEEK_END) < 0) break; // go back to where we were - - return; - } while (0); - - // One of the fseek()s failed, probable because we're not a seekable file - envir() << "AVIFileSink::setWord(): fseek failed (err " - << envir().getErrno() << ")\n"; -} - -// Methods for writing particular file headers. Note the following macros: - -#define addFileHeader(tag,name) \ - unsigned AVIFileSink::addFileHeader_##name() { \ - add4ByteString("" #tag ""); \ - unsigned headerSizePosn = ftell(fOutFid); addWord(0); \ - add4ByteString("" #name ""); \ - unsigned ignoredSize = 8;/*don't include size of tag or size fields*/ \ - unsigned size = 12 - -#define addFileHeader1(name) \ - unsigned AVIFileSink::addFileHeader_##name() { \ - add4ByteString("" #name ""); \ - unsigned headerSizePosn = ftell(fOutFid); addWord(0); \ - unsigned ignoredSize = 8;/*don't include size of name or size fields*/ \ - unsigned size = 8 - -#define addFileHeaderEnd \ - setWord(headerSizePosn, size-ignoredSize); \ - return size; \ -} - -addFileHeader(RIFF,AVI); - size += addFileHeader_hdrl(); - size += addFileHeader_movi(); - fRIFFSizePosition = headerSizePosn; - fRIFFSizeValue = size-ignoredSize; -addFileHeaderEnd; - -addFileHeader(LIST,hdrl); - size += addFileHeader_avih(); - - // Then, add a "strl" header for each subsession (stream): - // (Make the video subsession (if any) come before the audio subsession.) - unsigned subsessionCount = 0; - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - fCurrentIOState = (AVISubsessionIOState*)(subsession->miscPtr); - if (fCurrentIOState == NULL) continue; - if (strcmp(subsession->mediumName(), "video") != 0) continue; - - fCurrentIOState->setAVIstate(subsessionCount++); - size += addFileHeader_strl(); - } - iter.reset(); - while ((subsession = iter.next()) != NULL) { - fCurrentIOState = (AVISubsessionIOState*)(subsession->miscPtr); - if (fCurrentIOState == NULL) continue; - if (strcmp(subsession->mediumName(), "video") == 0) continue; - - fCurrentIOState->setAVIstate(subsessionCount++); - size += addFileHeader_strl(); - } - - // Then add another JUNK entry - ++fJunkNumber; - size += addFileHeader_JUNK(); -addFileHeaderEnd; - -#define AVIF_HASINDEX 0x00000010 // Index at end of file? -#define AVIF_MUSTUSEINDEX 0x00000020 -#define AVIF_ISINTERLEAVED 0x00000100 -#define AVIF_TRUSTCKTYPE 0x00000800 // Use CKType to find key frames? -#define AVIF_WASCAPTUREFILE 0x00010000 -#define AVIF_COPYRIGHTED 0x00020000 - -addFileHeader1(avih); - unsigned usecPerFrame = fMovieFPS == 0 ? 0 : 1000000/fMovieFPS; - size += addWord(usecPerFrame); // dwMicroSecPerFrame - fAVIHMaxBytesPerSecondPosition = ftell(fOutFid); - size += addWord(0); // dwMaxBytesPerSec (fill in later) - size += addWord(0); // dwPaddingGranularity - size += addWord(AVIF_TRUSTCKTYPE|AVIF_HASINDEX|AVIF_ISINTERLEAVED); // dwFlags - fAVIHFrameCountPosition = ftell(fOutFid); - size += addWord(0); // dwTotalFrames (fill in later) - size += addWord(0); // dwInitialFrame - size += addWord(fNumSubsessions); // dwStreams - size += addWord(fBufferSize); // dwSuggestedBufferSize - size += addWord(fMovieWidth); // dwWidth - size += addWord(fMovieHeight); // dwHeight - size += addZeroWords(4); // dwReserved -addFileHeaderEnd; - -addFileHeader(LIST,strl); - size += addFileHeader_strh(); - size += addFileHeader_strf(); - fJunkNumber = 0; - size += addFileHeader_JUNK(); -addFileHeaderEnd; - -addFileHeader1(strh); - size += add4ByteString(fCurrentIOState->fIsVideo ? "vids" : - fCurrentIOState->fIsAudio ? "auds" : - "????"); // fccType - size += addWord(fCurrentIOState->fAVICodecHandlerType); // fccHandler - size += addWord(0); // dwFlags - size += addWord(0); // wPriority + wLanguage - size += addWord(0); // dwInitialFrames - size += addWord(fCurrentIOState->fAVIScale); // dwScale - size += addWord(fCurrentIOState->fAVIRate); // dwRate - size += addWord(0); // dwStart - fCurrentIOState->fSTRHFrameCountPosition = ftell(fOutFid); - size += addWord(0); // dwLength (fill in later) - size += addWord(fBufferSize); // dwSuggestedBufferSize - size += addWord((unsigned)-1); // dwQuality - size += addWord(fCurrentIOState->fAVISize); // dwSampleSize - size += addWord(0); // rcFrame (start) - if (fCurrentIOState->fIsVideo) { - size += addHalfWord(fMovieWidth); - size += addHalfWord(fMovieHeight); - } else { - size += addWord(0); - } -addFileHeaderEnd; - -addFileHeader1(strf); - if (fCurrentIOState->fIsVideo) { - // Add a BITMAPINFO header: - unsigned extraDataSize = 0; - size += addWord(10*4 + extraDataSize); // size - size += addWord(fMovieWidth); - size += addWord(fMovieHeight); - size += addHalfWord(1); // planes - size += addHalfWord(24); // bits-per-sample ##### - size += addWord(fCurrentIOState->fAVICodecHandlerType); // compr. type - size += addWord(fCurrentIOState->fAVISize); - size += addZeroWords(4); // ??? ##### - // Later, add extra data here (if any) ##### - } else if (fCurrentIOState->fIsAudio) { - // Add a WAVFORMATEX header: - size += addHalfWord(fCurrentIOState->fWAVCodecTag); - unsigned numChannels = fCurrentIOState->fOurSubsession.numChannels(); - size += addHalfWord(numChannels); - size += addWord(fCurrentIOState->fAVISamplingFrequency); - size += addWord(fCurrentIOState->fAVIRate); // bytes per second - size += addHalfWord(fCurrentIOState->fAVISize); // block alignment - unsigned bitsPerSample = (fCurrentIOState->fAVISize*8)/numChannels; - size += addHalfWord(bitsPerSample); - if (strcmp(fCurrentIOState->fOurSubsession.codecName(), "MPA") == 0) { - // Assume MPEG layer II audio (not MP3): ##### - size += addHalfWord(22); // wav_extra_size - size += addHalfWord(2); // fwHeadLayer - size += addWord(8*fCurrentIOState->fAVIRate); // dwHeadBitrate ##### - size += addHalfWord(numChannels == 2 ? 1: 8); // fwHeadMode - size += addHalfWord(0); // fwHeadModeExt - size += addHalfWord(1); // wHeadEmphasis - size += addHalfWord(16); // fwHeadFlags - size += addWord(0); // dwPTSLow - size += addWord(0); // dwPTSHigh - } - } -addFileHeaderEnd; - -#define AVI_MASTER_INDEX_SIZE 256 - -addFileHeader1(JUNK); - if (fJunkNumber == 0) { - size += addHalfWord(4); // wLongsPerEntry - size += addHalfWord(0); // bIndexSubType + bIndexType - size += addWord(0); // nEntriesInUse ##### - size += addWord(fCurrentIOState->fAVISubsessionTag); // dwChunkId - size += addZeroWords(2); // dwReserved - size += addZeroWords(AVI_MASTER_INDEX_SIZE*4); - } else { - size += add4ByteString("odml"); - size += add4ByteString("dmlh"); - unsigned wtfCount = 248; - size += addWord(wtfCount); // ??? ##### - size += addZeroWords(wtfCount/4); - } -addFileHeaderEnd; - -addFileHeader(LIST,movi); - fMoviSizePosition = headerSizePosn; - fMoviSizeValue = size-ignoredSize; -addFileHeaderEnd; diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AudioInputDevice.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AudioInputDevice.cpp deleted file mode 100644 index 584dd5a5553..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AudioInputDevice.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 2001-2003 Live Networks, Inc. All rights reserved. -// Generic audio input device (such as a microphone, or an input sound card) -// Implementation - -#include - -AudioInputDevice -::AudioInputDevice(UsageEnvironment& env, unsigned char bitsPerSample, - unsigned char numChannels, - unsigned samplingFrequency, unsigned granularityInMS) - : FramedSource(env), fBitsPerSample(bitsPerSample), - fNumChannels(numChannels), fSamplingFrequency(samplingFrequency), - fGranularityInMS(granularityInMS) { -} - -AudioInputDevice::~AudioInputDevice() { -} - -char** AudioInputDevice::allowedDeviceNames = NULL; - -////////// AudioPortNames implementation ////////// - -AudioPortNames::AudioPortNames() -: numPorts(0), portName(NULL) { -} - -AudioPortNames::~AudioPortNames() { - for (unsigned i = 0; i < numPorts; ++i) delete portName[i]; - delete portName; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/AudioRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/AudioRTPSink.cpp deleted file mode 100644 index e7af41a101f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/AudioRTPSink.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A generic RTP sink for audio codecs (abstract base class) -// Implementation - -#include "AudioRTPSink.hh" - -AudioRTPSink::AudioRTPSink(UsageEnvironment& env, - Groupsock* rtpgs, unsigned char rtpPayloadType, - unsigned rtpTimestampFrequency, - char const* rtpPayloadFormatName, - unsigned numChannels) - : MultiFramedRTPSink(env, rtpgs, rtpPayloadType, rtpTimestampFrequency, - rtpPayloadFormatName, numChannels) { -} - -AudioRTPSink::~AudioRTPSink() { -} - -char const* AudioRTPSink::sdpMediaType() const { - return "audio"; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/Base64.cpp b/mythtv/libs/libmythlivemedia/liveMedia/Base64.cpp deleted file mode 100644 index 36987a46417..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/Base64.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Base64 encoding and decoding -// implementation - -#include "Base64.hh" -#include -#include - -static char base64DecodeTable[256]; - -static void initBase64DecodeTable() { - int i; - for (i = 0; i < 256; ++i) base64DecodeTable[i] = (char)0x80; - // default value: invalid - - for (i = 'A'; i <= 'Z'; ++i) base64DecodeTable[i] = 0 + (i - 'A'); - for (i = 'a'; i <= 'z'; ++i) base64DecodeTable[i] = 26 + (i - 'a'); - for (i = '0'; i <= '9'; ++i) base64DecodeTable[i] = 52 + (i - '0'); - base64DecodeTable[(unsigned char)'+'] = 62; - base64DecodeTable[(unsigned char)'/'] = 63; - base64DecodeTable[(unsigned char)'='] = 0; -} - -unsigned char* base64Decode(char* in, unsigned& resultSize, - Boolean trimTrailingZeros) { - static Boolean haveInitedBase64DecodeTable = False; - if (!haveInitedBase64DecodeTable) { - initBase64DecodeTable(); - haveInitedBase64DecodeTable = True; - } - - unsigned char* out = (unsigned char*)strDupSize(in); // ensures we have enough space - int k = 0; - int const jMax = strlen(in) - 3; - // in case "in" is not a multiple of 4 bytes (although it should be) - for (int j = 0; j < jMax; j += 4) { - char inTmp[4], outTmp[4]; - for (int i = 0; i < 4; ++i) { - inTmp[i] = in[i+j]; - outTmp[i] = base64DecodeTable[(unsigned char)inTmp[i]]; - if ((outTmp[i]&0x80) != 0) outTmp[i] = 0; // pretend the input was 'A' - } - - out[k++] = (outTmp[0]<<2) | (outTmp[1]>>4); - out[k++] = (outTmp[1]<<4) | (outTmp[2]>>2); - out[k++] = (outTmp[2]<<6) | outTmp[3]; - } - - if (trimTrailingZeros) { - while (k > 0 && out[k-1] == '\0') --k; - } - resultSize = k; - unsigned char* result = new unsigned char[resultSize]; - memmove(result, out, resultSize); - delete[] out; - - return result; -} - -static const char base64Char[] = -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -char* base64Encode(char const* orig) { - if (orig == NULL) return NULL; - - unsigned const origLength = strlen(orig); - unsigned const numOrig24BitValues = origLength/3; - Boolean havePadding = origLength > numOrig24BitValues*3; - Boolean havePadding2 = origLength == numOrig24BitValues*3 + 2; - unsigned const numResultBytes = 4*(numOrig24BitValues + havePadding); - char* result = new char[numResultBytes+1]; // allow for trailing '\0' - - // Map each full group of 3 input bytes into 4 output base-64 characters: - unsigned i; - for (i = 0; i < numOrig24BitValues; ++i) { - result[4*i+0] = base64Char[(orig[3*i]>>2)&0x3F]; - result[4*i+1] = base64Char[(((orig[3*i]&0x3)<<4) | (orig[3*i+1]>>4))&0x3F]; - result[4*i+2] = base64Char[((orig[3*i+1]<<2) | (orig[3*i+2]>>6))&0x3F]; - result[4*i+3] = base64Char[orig[3*i+2]&0x3F]; - } - - // Now, take padding into account. (Note: i == numOrig24BitValues) - if (havePadding) { - result[4*i+0] = base64Char[(orig[3*i]>>2)&0x3F]; - result[4*i+1] = base64Char[(((orig[3*i]&0x3)<<4) | (orig[3*i+1]>>4))&0x3F]; - if (havePadding2) { - result[4*i+2] = base64Char[(orig[3*i+1]<<2)&0x3F]; - } else { - result[4*i+2] = '='; - } - result[4*i+3] = '='; - } - - result[numResultBytes] = '\0'; - return result; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/BasicUDPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/BasicUDPSink.cpp deleted file mode 100644 index dc44b7ccb89..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/BasicUDPSink.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simple UDP sink (i.e., without RTP or other headers added); one frame per packet -// Implementation - -#include "BasicUDPSink.hh" -#include - -BasicUDPSink* BasicUDPSink::createNew(UsageEnvironment& env, Groupsock* gs, - unsigned maxPayloadSize) { - return new BasicUDPSink(env, gs, maxPayloadSize); -} - -BasicUDPSink::BasicUDPSink(UsageEnvironment& env, Groupsock* gs, - unsigned maxPayloadSize) - : MediaSink(env), - fGS(gs), fMaxPayloadSize(maxPayloadSize) { - fOutputBuffer = new unsigned char[fMaxPayloadSize]; -} - -BasicUDPSink::~BasicUDPSink() { - delete[] fOutputBuffer; -} - -Boolean BasicUDPSink::continuePlaying() { - // Record the fact that we're starting to play now: - gettimeofday(&fNextSendTime, NULL); - - // Arrange to get and send the first payload. - // (This will also schedule any future sends.) - continuePlaying1(); - return True; -} - -void BasicUDPSink::continuePlaying1() { - if (fSource != NULL) { - fSource->getNextFrame(fOutputBuffer, fMaxPayloadSize, - afterGettingFrame, this, - onSourceClosure, this); - } -} - -void BasicUDPSink::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval /*presentationTime*/, - unsigned durationInMicroseconds) { - BasicUDPSink* sink = (BasicUDPSink*)clientData; - sink->afterGettingFrame1(frameSize, numTruncatedBytes, durationInMicroseconds); -} - -void BasicUDPSink::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - unsigned durationInMicroseconds) { - if (numTruncatedBytes > 0) { - envir() << "BasicUDPSink::afterGettingFrame1(): The input frame data was too large for our spcified maximum payload size (" - << fMaxPayloadSize << "). " - << numTruncatedBytes << " bytes of trailing data was dropped!\n"; - } - - // Send the packet: - fGS->output(envir(), fGS->ttl(), fOutputBuffer, frameSize); - - // Figure out the time at which the next packet should be sent, based - // on the duration of the payload that we just read: - fNextSendTime.tv_usec += durationInMicroseconds; - fNextSendTime.tv_sec += fNextSendTime.tv_usec/1000000; - fNextSendTime.tv_usec %= 1000000; - - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - int uSecondsToGo; - if (fNextSendTime.tv_sec < timeNow.tv_sec) { - uSecondsToGo = 0; // prevents integer underflow if too far behind - } else { - uSecondsToGo = (fNextSendTime.tv_sec - timeNow.tv_sec)*1000000 - + (fNextSendTime.tv_usec - timeNow.tv_usec); - } - - // Delay this amount of time: - nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToGo, - (TaskFunc*)sendNext, this); -} - -// The following is called after each delay between packet sends: -void BasicUDPSink::sendNext(void* firstArg) { - BasicUDPSink* sink = (BasicUDPSink*)firstArg; - sink->continuePlaying1(); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/BasicUDPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/BasicUDPSource.cpp deleted file mode 100644 index 05a6c09d80b..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/BasicUDPSource.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simple UDP source, where every UDP payload is a complete frame -// Implementation - -#include "BasicUDPSource.hh" -#include - -BasicUDPSource* BasicUDPSource::createNew(UsageEnvironment& env, - Groupsock* inputGS) { - return new BasicUDPSource(env, inputGS); -} - -BasicUDPSource::BasicUDPSource(UsageEnvironment& env, Groupsock* inputGS) - : FramedSource(env), fInputGS(inputGS) { - // Try to use a large receive buffer (in the OS): - increaseReceiveBufferTo(env, inputGS->socketNum(), 50*1024); -} - -BasicUDPSource::~BasicUDPSource(){ - envir().taskScheduler().turnOffBackgroundReadHandling(fInputGS->socketNum()); -} - -void BasicUDPSource::doGetNextFrame() { - // Await the next incoming packet: - envir().taskScheduler().turnOnBackgroundReadHandling(fInputGS->socketNum(), - (TaskScheduler::BackgroundHandlerProc*)&incomingPacketHandler, this); -} - -void BasicUDPSource::doStopGettingFrames() { - envir().taskScheduler().turnOffBackgroundReadHandling(fInputGS->socketNum()); -} - - -void BasicUDPSource::incomingPacketHandler(BasicUDPSource* source, int /*mask*/){ - source->incomingPacketHandler1(); -} - -void BasicUDPSource::incomingPacketHandler1() { - if (!isCurrentlyAwaitingData()) return; // we're not ready for the data yet - - // Read the packet into our desired destination: - struct sockaddr_in fromAddress; - if (!fInputGS->handleRead(fTo, fMaxSize, fFrameSize, fromAddress)) return; - - // Tell our client that we have new data: - afterGetting(this); // we're preceded by a net read; no infinite recursion -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/BitVector.cpp b/mythtv/libs/libmythlivemedia/liveMedia/BitVector.cpp deleted file mode 100644 index 4817bd0c1c6..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/BitVector.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Bit Vector data structure -// Implementation - -#include "BitVector.hh" - -BitVector::BitVector(unsigned char* baseBytePtr, - unsigned baseBitOffset, - unsigned totNumBits) { - setup(baseBytePtr, baseBitOffset, totNumBits); -} - -void BitVector::setup(unsigned char* baseBytePtr, - unsigned baseBitOffset, - unsigned totNumBits) { - fBaseBytePtr = baseBytePtr; - fBaseBitOffset = baseBitOffset; - fTotNumBits = totNumBits; - fCurBitIndex = 0; -} - -static unsigned char const singleBitMask[8] - = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; - -#define MAX_LENGTH 32 - -void BitVector::putBits(unsigned from, unsigned numBits) { - unsigned char tmpBuf[4]; - unsigned overflowingBits = 0; - - if (numBits > MAX_LENGTH) { - numBits = MAX_LENGTH; - } - - if (numBits > fTotNumBits - fCurBitIndex) { - overflowingBits = numBits - (fTotNumBits - fCurBitIndex); - } - - tmpBuf[0] = (unsigned char)(from>>24); - tmpBuf[1] = (unsigned char)(from>>16); - tmpBuf[2] = (unsigned char)(from>>8); - tmpBuf[3] = (unsigned char)from; - - shiftBits(fBaseBytePtr, fBaseBitOffset + fCurBitIndex, /* to */ - tmpBuf, MAX_LENGTH - numBits, /* from */ - numBits - overflowingBits /* num bits */); - fCurBitIndex += numBits - overflowingBits; -} - - -void BitVector::put1Bit(unsigned bit) { - // The following is equivalent to "putBits(..., 1)", except faster: - if (fCurBitIndex >= fTotNumBits) { /* overflow */ - return; - } else { - unsigned totBitOffset = fBaseBitOffset + fCurBitIndex++; - unsigned char mask = singleBitMask[totBitOffset%8]; - if (bit) { - fBaseBytePtr[totBitOffset/8] |= mask; - } else { - fBaseBytePtr[totBitOffset/8] &=~ mask; - } - } -} - - -unsigned BitVector::getBits(unsigned numBits) { - unsigned char tmpBuf[4]; - unsigned overflowingBits = 0; - - if (numBits > MAX_LENGTH) { - numBits = MAX_LENGTH; - } - - if (numBits > fTotNumBits - fCurBitIndex) { - overflowingBits = numBits - (fTotNumBits - fCurBitIndex); - } - - shiftBits(tmpBuf, 0, /* to */ - fBaseBytePtr, fBaseBitOffset + fCurBitIndex, /* from */ - numBits - overflowingBits /* num bits */); - fCurBitIndex += numBits - overflowingBits; - - unsigned result - = (tmpBuf[0]<<24) | (tmpBuf[1]<<16) | (tmpBuf[2]<<8) | tmpBuf[3]; - result >>= (MAX_LENGTH - numBits); // move into low-order part of word - result &= (0xFFFFFFFF << overflowingBits); // so any overflow bits are 0 - return result; -} - -unsigned BitVector::get1Bit() { - // The following is equivalent to "getBits(1)", except faster: - - if (fCurBitIndex >= fTotNumBits) { /* overflow */ - return 0; - } else { - unsigned totBitOffset = fBaseBitOffset + fCurBitIndex++; - unsigned char curFromByte = fBaseBytePtr[totBitOffset/8]; - unsigned result = (curFromByte >> (7-(totBitOffset%8))) & 0x01; - return result; - } -} - -void BitVector::skipBits(unsigned numBits) { - if (numBits > fTotNumBits - fCurBitIndex) { /* overflow */ - fCurBitIndex = fTotNumBits; - } else { - fCurBitIndex += numBits; - } -} - - -void shiftBits(unsigned char* toBasePtr, unsigned toBitOffset, - unsigned char const* fromBasePtr, unsigned fromBitOffset, - unsigned numBits) { - /* Note that from and to may overlap, if from>to */ - unsigned char const* fromBytePtr = fromBasePtr + fromBitOffset/8; - unsigned fromBitRem = fromBitOffset%8; - unsigned char* toBytePtr = toBasePtr + toBitOffset/8; - unsigned toBitRem = toBitOffset%8; - - while (numBits-- > 0) { - unsigned char fromBitMask = singleBitMask[fromBitRem]; - unsigned char fromBit = (*fromBytePtr)&fromBitMask; - unsigned char toBitMask = singleBitMask[toBitRem]; - - if (fromBit != 0) { - *toBytePtr |= toBitMask; - } else { - *toBytePtr &=~ toBitMask; - } - - if (++fromBitRem == 8) { - ++fromBytePtr; - fromBitRem = 0; - } - if (++toBitRem == 8) { - ++toBytePtr; - toBitRem = 0; - } - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/BitVector.hh b/mythtv/libs/libmythlivemedia/liveMedia/BitVector.hh deleted file mode 100644 index b8b74a130b7..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/BitVector.hh +++ /dev/null @@ -1,58 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Bit Vector data structure -// C++ header - -#ifndef _BIT_VECTOR_HH -#define _BIT_VECTOR_HH - -class BitVector { -public: - BitVector(unsigned char* baseBytePtr, - unsigned baseBitOffset, - unsigned totNumBits); - - void setup(unsigned char* baseBytePtr, - unsigned baseBitOffset, - unsigned totNumBits); - - void putBits(unsigned from, unsigned numBits); // "numBits" <= 32 - void put1Bit(unsigned bit); - - unsigned getBits(unsigned numBits); // "numBits" <= 32 - unsigned get1Bit(); - - void skipBits(unsigned numBits); - - unsigned curBitIndex() const { return fCurBitIndex; } - unsigned totNumBits() const { return fTotNumBits; } - unsigned numBitsRemaining() const { return fTotNumBits - fCurBitIndex; } - -private: - unsigned char* fBaseBytePtr; - unsigned fBaseBitOffset; - unsigned fTotNumBits; - unsigned fCurBitIndex; -}; - -// A general bit copy operation: -void shiftBits(unsigned char* toBasePtr, unsigned toBitOffset, - unsigned char const* fromBasePtr, unsigned fromBitOffset, - unsigned numBits); - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/ByteStreamFileSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/ByteStreamFileSource.cpp deleted file mode 100644 index 0b55ff57e9a..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/ByteStreamFileSource.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A file source that is a plain byte stream (rather than frames) -// Implementation - -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE) -#include -#include -#endif - -#include "ByteStreamFileSource.hh" -#include "InputFile.hh" -#include "GroupsockHelper.hh" - -////////// ByteStreamFileSource ////////// - -ByteStreamFileSource* -ByteStreamFileSource::createNew(UsageEnvironment& env, char const* fileName, - unsigned preferredFrameSize, - unsigned playTimePerFrame) { - FILE* fid = OpenInputFile(env, fileName); - if (fid == NULL) return NULL; - - Boolean deleteFidOnClose = fid == stdin ? False : True; - ByteStreamFileSource* newSource - = new ByteStreamFileSource(env, fid, deleteFidOnClose, - preferredFrameSize, playTimePerFrame); - newSource->fFileSize = GetFileSize(fileName, fid); - - return newSource; -} - -ByteStreamFileSource* -ByteStreamFileSource::createNew(UsageEnvironment& env, FILE* fid, - Boolean deleteFidOnClose, - unsigned preferredFrameSize, - unsigned playTimePerFrame) { - if (fid == NULL) return NULL; - - ByteStreamFileSource* newSource - = new ByteStreamFileSource(env, fid, deleteFidOnClose, - preferredFrameSize, playTimePerFrame); - newSource->fFileSize = GetFileSize(NULL, fid); - - return newSource; -} - -void ByteStreamFileSource::seekToByteAbsolute(u_int64_t byteNumber) { - SeekFile64(fFid, (int64_t)byteNumber, SEEK_SET); -} - -void ByteStreamFileSource::seekToByteRelative(int64_t offset) { - SeekFile64(fFid, offset, SEEK_CUR); -} - -ByteStreamFileSource::ByteStreamFileSource(UsageEnvironment& env, FILE* fid, - Boolean deleteFidOnClose, - unsigned preferredFrameSize, - unsigned playTimePerFrame) - : FramedFileSource(env, fid), fPreferredFrameSize(preferredFrameSize), - fPlayTimePerFrame(playTimePerFrame), fLastPlayTime(0), fFileSize(0), - fDeleteFidOnClose(deleteFidOnClose) { -} - -ByteStreamFileSource::~ByteStreamFileSource() { - if (fDeleteFidOnClose && fFid != NULL) fclose(fFid); -} - -void ByteStreamFileSource::doGetNextFrame() { - if (feof(fFid) || ferror(fFid)) { - handleClosure(this); - return; - } - - // Try to read as many bytes as will fit in the buffer provided - // (or "fPreferredFrameSize" if less) - if (fPreferredFrameSize > 0 && fPreferredFrameSize < fMaxSize) { - fMaxSize = fPreferredFrameSize; - } - fFrameSize = fread(fTo, 1, fMaxSize, fFid); - - // Set the 'presentation time': - if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) { - if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) { - // This is the first frame, so use the current time: - gettimeofday(&fPresentationTime, NULL); - } else { - // Increment by the play time of the previous data: - unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime; - fPresentationTime.tv_sec += uSeconds/1000000; - fPresentationTime.tv_usec = uSeconds%1000000; - } - - // Remember the play time of this data: - fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize; - fDurationInMicroseconds = fLastPlayTime; - } else { - // We don't know a specific play time duration for this data, - // so just record the current time as being the 'presentation time': - gettimeofday(&fPresentationTime, NULL); - } - - // Switch to another task, and inform the reader that he has data: - nextTask() = envir().taskScheduler().scheduleDelayedTask(0, - (TaskFunc*)FramedSource::afterGetting, this); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/ByteStreamMultiFileSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/ByteStreamMultiFileSource.cpp deleted file mode 100644 index 06b8e0667c9..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/ByteStreamMultiFileSource.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A source that consists of multiple byte-stream files, read sequentially -// Implementation - -#include "ByteStreamMultiFileSource.hh" - -ByteStreamMultiFileSource -::ByteStreamMultiFileSource(UsageEnvironment& env, char const** fileNameArray, - unsigned preferredFrameSize, unsigned playTimePerFrame) - : FramedSource(env), - fPreferredFrameSize(preferredFrameSize), fPlayTimePerFrame(playTimePerFrame), - fCurrentlyReadSourceNumber(0), fHaveStartedNewFile(False) { - // Begin by counting the number of sources: - for (fNumSources = 0; ; ++fNumSources) { - if (fileNameArray[fNumSources] == NULL) break; - } - - // Next, copy the source file names into our own array: - fFileNameArray = new char const*[fNumSources]; - if (fFileNameArray == NULL) return; - unsigned i; - for (i = 0; i < fNumSources; ++i) { - fFileNameArray[i] = strDup(fileNameArray[i]); - } - - // Next, set up our array of component ByteStreamFileSources - // Don't actually create these yet; instead, do this on demand - fSourceArray = new ByteStreamFileSource*[fNumSources]; - if (fSourceArray == NULL) return; - for (i = 0; i < fNumSources; ++i) { - fSourceArray[i] = NULL; - } -} - -ByteStreamMultiFileSource::~ByteStreamMultiFileSource() { - unsigned i; - for (i = 0; i < fNumSources; ++i) { - Medium::close(fSourceArray[i]); - } - delete[] fSourceArray; - - for (i = 0; i < fNumSources; ++i) { - delete[] (char*)(fFileNameArray[i]); - } - delete[] fFileNameArray; -} - -ByteStreamMultiFileSource* ByteStreamMultiFileSource -::createNew(UsageEnvironment& env, char const** fileNameArray, - unsigned preferredFrameSize, unsigned playTimePerFrame) { - ByteStreamMultiFileSource* newSource - = new ByteStreamMultiFileSource(env, fileNameArray, - preferredFrameSize, playTimePerFrame); - - return newSource; -} - -void ByteStreamMultiFileSource::doGetNextFrame() { - do { - // First, check whether we've run out of sources: - if (fCurrentlyReadSourceNumber >= fNumSources) break; - - fHaveStartedNewFile = False; - ByteStreamFileSource*& source - = fSourceArray[fCurrentlyReadSourceNumber]; - if (source == NULL) { - // The current source hasn't been created yet. Do this now: - source = ByteStreamFileSource::createNew(envir(), - fFileNameArray[fCurrentlyReadSourceNumber], - fPreferredFrameSize, fPlayTimePerFrame); - if (source == NULL) break; - fHaveStartedNewFile = True; - } - - // (Attempt to) read from the current source. - source->getNextFrame(fTo, fMaxSize, - afterGettingFrame, this, - onSourceClosure, this); - return; - } while (0); - - // An error occurred; consider ourselves closed: - handleClosure(this); -} - -void ByteStreamMultiFileSource - ::afterGettingFrame(void* clientData, - unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - ByteStreamMultiFileSource* source - = (ByteStreamMultiFileSource*)clientData; - source->fFrameSize = frameSize; - source->fNumTruncatedBytes = numTruncatedBytes; - source->fPresentationTime = presentationTime; - source->fDurationInMicroseconds = durationInMicroseconds; - FramedSource::afterGetting(source); -} - -void ByteStreamMultiFileSource::onSourceClosure(void* clientData) { - ByteStreamMultiFileSource* source - = (ByteStreamMultiFileSource*)clientData; - source->onSourceClosure1(); -} - -void ByteStreamMultiFileSource::onSourceClosure1() { - // This routine was called because the currently-read source was closed - // (probably due to EOF). Close this source down, and move to the - // next one: - ByteStreamFileSource*& source - = fSourceArray[fCurrentlyReadSourceNumber++]; - Medium::close(source); - source = NULL; - - // Try reading again: - doGetNextFrame(); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/COPYING b/mythtv/libs/libmythlivemedia/liveMedia/COPYING deleted file mode 100644 index 3b204400cf3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/COPYING +++ /dev/null @@ -1,458 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS diff --git a/mythtv/libs/libmythlivemedia/liveMedia/DarwinInjector.cpp b/mythtv/libs/libmythlivemedia/liveMedia/DarwinInjector.cpp deleted file mode 100644 index c62f194879f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/DarwinInjector.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// An object that redirects one or more RTP/RTCP streams - forming a single -// multimedia session - into a 'Darwin Streaming Server' (for subsequent -// reflection to potentially arbitrarily many remote RTSP clients). -// Implementation. - -#include "DarwinInjector.hh" -#include - -////////// SubstreamDescriptor definition ////////// - -class SubstreamDescriptor { -public: - SubstreamDescriptor(RTPSink* rtpSink, RTCPInstance* rtcpInstance); - ~SubstreamDescriptor(); - - SubstreamDescriptor*& next() { return fNext; } - RTPSink* rtpSink() const { return fRTPSink; } - RTCPInstance* rtcpInstance() const { return fRTCPInstance; } - char const* sdpLines() const { return fSDPLines; } - -private: - SubstreamDescriptor* fNext; - RTPSink* fRTPSink; - RTCPInstance* fRTCPInstance; - char* fSDPLines; -}; - - -////////// DarwinInjector implementation ////////// - -DarwinInjector* DarwinInjector::createNew(UsageEnvironment& env, - char const* applicationName, - int verbosityLevel) { - return new DarwinInjector(env, applicationName, verbosityLevel); -} - -Boolean DarwinInjector::lookupByName(UsageEnvironment& env, char const* name, - DarwinInjector*& result) { - result = NULL; // unless we succeed - - Medium* medium; - if (!Medium::lookupByName(env, name, medium)) return False; - - if (!medium->isDarwinInjector()) { - env.setResultMsg(name, " is not a 'Darwin injector'"); - return False; - } - - result = (DarwinInjector*)medium; - return True; -} - -DarwinInjector::DarwinInjector(UsageEnvironment& env, - char const* applicationName, int verbosityLevel) - : Medium(env), - fApplicationName(applicationName), fVerbosityLevel(verbosityLevel), - fRTSPClient(NULL), fSubstreamSDPSizes(0), - fHeadSubstream(NULL), fTailSubstream(NULL) { -} - -DarwinInjector::~DarwinInjector() { - delete fHeadSubstream; - Medium::close(fRTSPClient); -} - -void DarwinInjector::addStream(RTPSink* rtpSink, RTCPInstance* rtcpInstance) { - if (rtpSink == NULL) return; // "rtpSink" should be non-NULL - - SubstreamDescriptor* newDescriptor = new SubstreamDescriptor(rtpSink, rtcpInstance); - if (fHeadSubstream == NULL) { - fHeadSubstream = fTailSubstream = newDescriptor; - } else { - fTailSubstream->next() = newDescriptor; - fTailSubstream = newDescriptor; - } - - fSubstreamSDPSizes += strlen(newDescriptor->sdpLines()); -} - -Boolean DarwinInjector -::setDestination(char const* remoteRTSPServerNameOrAddress, - char const* remoteFileName, - char const* sessionName, - char const* sessionInfo, - portNumBits remoteRTSPServerPortNumber, - char const* remoteUserName, - char const* remotePassword, - char const* sessionAuthor, - char const* sessionCopyright) { - char* sdp = NULL; - char* url = NULL; - MediaSession* session = NULL; - Boolean success = False; // until we learn otherwise - - do { - // Begin by creating our RTSP client object: - fRTSPClient = RTSPClient::createNew(envir(), fVerbosityLevel, fApplicationName); - if (fRTSPClient == NULL) break; - - // Get the remote RTSP server's IP address: - struct in_addr addr; - { - NetAddressList addresses(remoteRTSPServerNameOrAddress); - if (addresses.numAddresses() == 0) break; - NetAddress const* address = addresses.firstAddress(); - addr.s_addr = *(unsigned*)(address->data()); - } - char const* remoteRTSPServerAddressStr = our_inet_ntoa(addr); - - // Construct a SDP description for the session that we'll be streaming: - char const* const sdpFmt = - "v=0\r\n" - "o=- %u %u IN IP4 127.0.0.1\r\n" - "s=%s\r\n" - "i=%s\r\n" - "c=IN IP4 %s\r\n" - "t=0 0\r\n" - "a=x-qt-text-nam:%s\r\n" - "a=x-qt-text-inf:%s\r\n" - "a=x-qt-text-cmt:%s\r\n" - "a=x-qt-text-aut:%s\r\n" - "a=x-qt-text-cpy:%s\r\n"; - // plus, %s for each substream SDP - unsigned sdpLen = strlen(sdpFmt) - + 20 /* max int len */ + 20 /* max int len */ - + strlen(sessionName) - + strlen(sessionInfo) - + strlen(remoteRTSPServerAddressStr) - + strlen(sessionName) - + strlen(sessionInfo) - + strlen(fApplicationName) - + strlen(sessionAuthor) - + strlen(sessionCopyright) - + fSubstreamSDPSizes; - unsigned const sdpSessionId = our_random(); - unsigned const sdpVersion = sdpSessionId; - sdp = new char[sdpLen]; - sprintf(sdp, sdpFmt, - sdpSessionId, sdpVersion, // o= line - sessionName, // s= line - sessionInfo, // i= line - remoteRTSPServerAddressStr, // c= line - sessionName, // a=x-qt-text-nam: line - sessionInfo, // a=x-qt-text-inf: line - fApplicationName, // a=x-qt-text-cmt: line - sessionAuthor, // a=x-qt-text-aut: line - sessionCopyright // a=x-qt-text-cpy: line - ); - char* p = &sdp[strlen(sdp)]; - SubstreamDescriptor* ss; - for (ss = fHeadSubstream; ss != NULL; ss = ss->next()) { - sprintf(p, "%s", ss->sdpLines()); - p += strlen(p); - } - - // Construct a RTSP URL for the remote stream: - char const* const urlFmt = "rtsp://%s:%u/%s"; - unsigned urlLen - = strlen(urlFmt) + strlen(remoteRTSPServerNameOrAddress) + 5 /* max short len */ + strlen(remoteFileName); - url = new char[urlLen]; - sprintf(url, urlFmt, remoteRTSPServerNameOrAddress, remoteRTSPServerPortNumber, remoteFileName); - - // Do a RTSP "ANNOUNCE" with this SDP description: - Boolean announceSuccess; - if (remoteUserName[0] != '\0' || remotePassword[0] != '\0') { - announceSuccess - = fRTSPClient->announceWithPassword(url, sdp, remoteUserName, remotePassword); - } else { - announceSuccess = fRTSPClient->announceSDPDescription(url, sdp); - } - if (!announceSuccess) break; - - // Tell the remote server to start receiving the stream from us. - // (To do this, we first create a "MediaSession" object from the SDP description.) - session = MediaSession::createNew(envir(), sdp); - if (session == NULL) break; - - ss = fHeadSubstream; - MediaSubsessionIterator iter(*session); - MediaSubsession* subsession; - ss = fHeadSubstream; - unsigned streamChannelId = 0; - while ((subsession = iter.next()) != NULL) { - if (!subsession->initiate()) break; - - if (!fRTSPClient->setupMediaSubsession(*subsession, - True /*streamOutgoing*/, - True /*streamUsingTCP*/)) { - break; - } - - // Tell this subsession's RTPSink and RTCPInstance to use - // the RTSP TCP connection: - ss->rtpSink()->setStreamSocket(fRTSPClient->socketNum(), streamChannelId++); - if (ss->rtcpInstance() != NULL) { - ss->rtcpInstance()->setStreamSocket(fRTSPClient->socketNum(), - streamChannelId++); - } - ss = ss->next(); - } - if (subsession != NULL) break; // an error occurred above - - // Tell the RTSP server to start: - if (!fRTSPClient->playMediaSession(*session)) break; - - // Finally, make sure that the output TCP buffer is a reasonable size: - increaseSendBufferTo(envir(), fRTSPClient->socketNum(), 100*1024); - - success = True; - } while (0); - - delete[] sdp; - delete[] url; - Medium::close(session); - return success; -} - -Boolean DarwinInjector::isDarwinInjector() const { - return True; -} - - -////////// SubstreamDescriptor implementation ////////// - -static unsigned lastTrackId = 0; - -SubstreamDescriptor::SubstreamDescriptor(RTPSink* rtpSink, - RTCPInstance* rtcpInstance) - : fNext(NULL), fRTPSink(rtpSink), fRTCPInstance(rtcpInstance) { - // Create the SDP description for this substream - char const* mediaType = fRTPSink->sdpMediaType(); - unsigned char rtpPayloadType = fRTPSink->rtpPayloadType(); - char const* rtpPayloadFormatName = fRTPSink->rtpPayloadFormatName(); - unsigned rtpTimestampFrequency = fRTPSink->rtpTimestampFrequency(); - unsigned numChannels = fRTPSink->numChannels(); - char* rtpmapLine; - if (rtpPayloadType >= 96) { - char* encodingParamsPart; - if (numChannels != 1) { - encodingParamsPart = new char[1 + 20 /* max int len */]; - sprintf(encodingParamsPart, "/%d", numChannels); - } else { - encodingParamsPart = strDup(""); - } - char const* const rtpmapFmt = "a=rtpmap:%d %s/%d%s\r\n"; - unsigned rtpmapFmtSize = strlen(rtpmapFmt) - + 3 /* max char len */ + strlen(rtpPayloadFormatName) - + 20 /* max int len */ + strlen(encodingParamsPart); - rtpmapLine = new char[rtpmapFmtSize]; - sprintf(rtpmapLine, rtpmapFmt, - rtpPayloadType, rtpPayloadFormatName, - rtpTimestampFrequency, encodingParamsPart); - delete[] encodingParamsPart; - } else { - // Static payload type => no "a=rtpmap:" line - rtpmapLine = strDup(""); - } - unsigned rtpmapLineSize = strlen(rtpmapLine); - char const* auxSDPLine = fRTPSink->auxSDPLine(); - if (auxSDPLine == NULL) auxSDPLine = ""; - unsigned auxSDPLineSize = strlen(auxSDPLine); - - char const* const sdpFmt = - "m=%s 0 RTP/AVP %u\r\n" - "%s" // "a=rtpmap:" line (if present) - "%s" // auxilliary (e.g., "a=fmtp:") line (if present) - "a=control:trackID=%u\r\n"; - unsigned sdpFmtSize = strlen(sdpFmt) - + strlen(mediaType) + 3 /* max char len */ - + rtpmapLineSize - + auxSDPLineSize - + 20 /* max int len */; - char* sdpLines = new char[sdpFmtSize]; - sprintf(sdpLines, sdpFmt, - mediaType, // m= - rtpPayloadType, // m= - rtpmapLine, // a=rtpmap:... (if present) - auxSDPLine, // optional extra SDP line - ++lastTrackId); // a=control: - fSDPLines = strDup(sdpLines); - delete[] sdpLines; - delete[] rtpmapLine; -} - -SubstreamDescriptor::~SubstreamDescriptor() { - delete fSDPLines; - delete fNext; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/DeviceSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/DeviceSource.cpp deleted file mode 100644 index f93023ed916..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/DeviceSource.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A template for a MediaSource encapsulating an audio/video input device -// Implementation - -#include "DeviceSource.hh" - -DeviceSource* -DeviceSource::createNew(UsageEnvironment& env, - DeviceParameters params) { - return new DeviceSource(env, params); -} - -DeviceSource::DeviceSource(UsageEnvironment& env, - DeviceParameters params) - : FramedSource(env), fParams(params) { - // Any initialization of the device would be done here -} - -DeviceSource::~DeviceSource() { -} - -void DeviceSource::doGetNextFrame() { - - // Arrange here for our "deliverFrame" member function to be called - // when the next frame of data becomes available from the device. - // This must be done in a non-blocking fashion - i.e., so that we - // return immediately from this function even if no data is - // currently available. - // - // If the device can be implemented as a readable socket, then one easy - // way to do this is using a call to - // envir().taskScheduler().turnOnBackgroundReadHandling( ... ) - // (See examples of this call in the "liveMedia" directory.) - - // If, for some reason, the source device stops being readable - // (e.g., it gets closed), then you do the following: - if (0 /* the source stops being readable */) { - handleClosure(this); - return; - } -} - -void DeviceSource::deliverFrame() { - // This would be called when new frame data is available from the device. - // This function should deliver the next frame of data from the device, - // using the following parameters (class members): - // 'in' parameters (these should *not* be modified by this function): - // fTo: The frame data is copied to this address. - // (Note that the variable "fTo" is *not* modified. Instead, - // the frame data is copied to the address pointed to by "fTo".) - // fMaxSize: This is the maximum number of bytes that can be copied - // (If the actual frame is larger than this, then it should - // be truncated, and "fNumTruncatedBytes" set accordingly.) - // 'out' parameters (these are modified by this function): - // fFrameSize: Should be set to the delivered frame size (<= fMaxSize). - // fNumTruncatedBytes: Should be set iff the delivered frame would have been - // bigger than "fMaxSize", in which case it's set to the number of bytes - // that have been omitted. - // fPresentationTime: Should be set to the frame's presentation time - // (seconds, microseconds). - // fDurationInMicroseconds: Should be set to the frame's duration, if known. - if (!isCurrentlyAwaitingData()) return; // we're not ready for the data yet - - // Deliver the data here: - - // After delivering the data, switch to another task, and inform - // the reader that he has data: - nextTask() - = envir().taskScheduler().scheduleDelayedTask(0, (TaskFunc*)afterGetting, - this); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/DigestAuthentication.cpp b/mythtv/libs/libmythlivemedia/liveMedia/DigestAuthentication.cpp deleted file mode 100644 index 0bca2cf1b73..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/DigestAuthentication.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A class used for digest authentication. -// Implementation - -#include "DigestAuthentication.hh" -#include "our_md5.h" -#include -#include // for gettimeofday() -#include -#include -#include - -Authenticator::Authenticator() { - assign(NULL, NULL, NULL, NULL, False); -} - -Authenticator::Authenticator(const Authenticator& orig) { - assign(orig.realm(), orig.nonce(), orig.username(), orig.password(), - orig.fPasswordIsMD5); -} - -Authenticator& Authenticator::operator=(const Authenticator& rightSide) { - if (&rightSide != this) { - reset(); - assign(rightSide.realm(), rightSide.nonce(), - rightSide.username(), rightSide.password(), rightSide.fPasswordIsMD5); - } - - return *this; -} - -Authenticator::~Authenticator() { - reset(); -} - -void Authenticator::reset() { - resetRealmAndNonce(); - resetUsernameAndPassword(); -} - -void Authenticator::setRealmAndNonce(char const* realm, char const* nonce) { - resetRealmAndNonce(); - assignRealmAndNonce(realm, nonce); -} - -void Authenticator::setRealmAndRandomNonce(char const* realm) { - resetRealmAndNonce(); - - // Construct data to seed the random nonce: - struct { - struct timeval timestamp; - unsigned counter; - } seedData; - gettimeofday(&seedData.timestamp, NULL); - static unsigned counter = 0; - seedData.counter = ++counter; - - // Use MD5 to compute a 'random' nonce from this seed data: - char nonceBuf[33]; - our_MD5Data((unsigned char*)(&seedData), sizeof seedData, nonceBuf); - - assignRealmAndNonce(realm, nonceBuf); -} - -void Authenticator::setUsernameAndPassword(char const* username, - char const* password, - Boolean passwordIsMD5) { - resetUsernameAndPassword(); - assignUsernameAndPassword(username, password, passwordIsMD5); -} - -char const* Authenticator::computeDigestResponse(char const* cmd, - char const* url) const { - // The "response" field is computed as: - // md5(md5(::)::md5(:)) - // or, if "fPasswordIsMD5" is True: - // md5(::md5(:)) - char ha1Buf[33]; - if (fPasswordIsMD5) { - strncpy(ha1Buf, password(), 32); - ha1Buf[32] = '\0'; // just in case - } else { - unsigned const ha1DataLen = strlen(username()) + 1 - + strlen(realm()) + 1 + strlen(password()); - unsigned char* ha1Data = new unsigned char[ha1DataLen+1]; - sprintf((char*)ha1Data, "%s:%s:%s", username(), realm(), password()); - our_MD5Data(ha1Data, ha1DataLen, ha1Buf); - delete[] ha1Data; - } - - unsigned const ha2DataLen = strlen(cmd) + 1 + strlen(url); - unsigned char* ha2Data = new unsigned char[ha2DataLen+1]; - sprintf((char*)ha2Data, "%s:%s", cmd, url); - char ha2Buf[33]; - our_MD5Data(ha2Data, ha2DataLen, ha2Buf); - delete[] ha2Data; - - unsigned const digestDataLen - = 32 + 1 + strlen(nonce()) + 1 + 32; - unsigned char* digestData = new unsigned char[digestDataLen+1]; - sprintf((char*)digestData, "%s:%s:%s", - ha1Buf, nonce(), ha2Buf); - char const* result = our_MD5Data(digestData, digestDataLen, NULL); - delete[] digestData; - return result; -} - -void Authenticator::reclaimDigestResponse(char const* responseStr) const { - free((char*)responseStr); // NOT delete, because it was malloc-allocated -} - -void Authenticator::resetRealmAndNonce() { - delete fRealm; fRealm = NULL; - delete fNonce; fNonce = NULL; -} - -void Authenticator::resetUsernameAndPassword() { - delete fUsername; fUsername = NULL; - delete fPassword; fPassword = NULL; - fPasswordIsMD5 = False; -} - -void Authenticator::assignRealmAndNonce(char const* realm, char const* nonce) { - fRealm = strDup(realm); - fNonce = strDup(nonce); -} - -void Authenticator -::assignUsernameAndPassword(char const* username, char const* password, - Boolean passwordIsMD5) { - fUsername = strDup(username); - fPassword = strDup(password); - fPasswordIsMD5 = passwordIsMD5; -} - -void Authenticator::assign(char const* realm, char const* nonce, - char const* username, char const* password, - Boolean passwordIsMD5) { - assignRealmAndNonce(realm, nonce); - assignUsernameAndPassword(username, password, passwordIsMD5); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/FileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/FileServerMediaSubsession.cpp deleted file mode 100644 index 54ad27bf042..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/FileServerMediaSubsession.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a file. -// Implementation - -#include "FileServerMediaSubsession.hh" - -FileServerMediaSubsession -::FileServerMediaSubsession(UsageEnvironment& env, char const* fileName, - Boolean reuseFirstSource) - : OnDemandServerMediaSubsession(env, reuseFirstSource), - fFileSize(0) { - fFileName = strDup(fileName); -} - -FileServerMediaSubsession::~FileServerMediaSubsession() { - delete[] (char*)fFileName; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/FileSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/FileSink.cpp deleted file mode 100644 index 1bf1165d152..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/FileSink.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// File sinks -// Implementation - -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE) -#include -#include -#endif -#include "FileSink.hh" -#include "GroupsockHelper.hh" -#include "OutputFile.hh" - -////////// FileSink ////////// - -FileSink::FileSink(UsageEnvironment& env, FILE* fid, unsigned bufferSize, - char const* perFrameFileNamePrefix) - : MediaSink(env), fOutFid(fid), fBufferSize(bufferSize) { - fBuffer = new unsigned char[bufferSize]; - if (perFrameFileNamePrefix != NULL) { - fPerFrameFileNamePrefix = strDup(perFrameFileNamePrefix); - fPerFrameFileNameBuffer = new char[strlen(perFrameFileNamePrefix) + 100]; - } else { - fPerFrameFileNamePrefix = NULL; - fPerFrameFileNameBuffer = NULL; - } -} - -FileSink::~FileSink() { - delete[] fPerFrameFileNameBuffer; - delete[] fPerFrameFileNamePrefix; - delete[] fBuffer; - if (fOutFid != NULL) fclose(fOutFid); -} - -FileSink* FileSink::createNew(UsageEnvironment& env, char const* fileName, - unsigned bufferSize, Boolean oneFilePerFrame) { - do { - FILE* fid; - char const* perFrameFileNamePrefix; - if (oneFilePerFrame) { - // Create the fid for each frame - fid = NULL; - perFrameFileNamePrefix = fileName; - } else { - // Normal case: create the fid once - fid = OpenOutputFile(env, fileName); - if (fid == NULL) break; - perFrameFileNamePrefix = NULL; - } - - return new FileSink(env, fid, bufferSize, perFrameFileNamePrefix); - } while (0); - - return NULL; -} - -Boolean FileSink::continuePlaying() { - if (fSource == NULL) return False; - - fSource->getNextFrame(fBuffer, fBufferSize, - afterGettingFrame, this, - onSourceClosure, this); - - return True; -} - -void FileSink::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - FileSink* sink = (FileSink*)clientData; - sink->afterGettingFrame1(frameSize, presentationTime); -} - -void FileSink::addData(unsigned char* data, unsigned dataSize, - struct timeval presentationTime) { - if (fPerFrameFileNameBuffer != NULL) { - // Special case: Open a new file on-the-fly for this frame - sprintf(fPerFrameFileNameBuffer, "%s-%lu.%06lu", fPerFrameFileNamePrefix, - presentationTime.tv_sec, presentationTime.tv_usec); - fOutFid = OpenOutputFile(envir(), fPerFrameFileNameBuffer); - } - - // Write to our file: -#ifdef TEST_LOSS - static unsigned const framesPerPacket = 10; - static unsigned const frameCount = 0; - static Boolean const packetIsLost; - if ((frameCount++)%framesPerPacket == 0) { - packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss ##### - } - - if (!packetIsLost) -#endif - if (fOutFid != NULL && data != NULL) { - fwrite(data, 1, dataSize, fOutFid); - } -} - -void FileSink::afterGettingFrame1(unsigned frameSize, - struct timeval presentationTime) { - addData(fBuffer, frameSize, presentationTime); - - if (fOutFid == NULL || fflush(fOutFid) == EOF) { - // The output file has closed. Handle this the same way as if the - // input source had closed: - onSourceClosure(this); - - stopPlaying(); - return; - } - - if (fPerFrameFileNameBuffer != NULL) { - if (fOutFid != NULL) { fclose(fOutFid); fOutFid = NULL; } - } - - // Then try getting the next frame: - continuePlaying(); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/FramedFileSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/FramedFileSource.cpp deleted file mode 100644 index 10311b3227d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/FramedFileSource.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Framed File Sources -// Implementation - -#include "FramedFileSource.hh" - -////////// FramedFileSource ////////// - -FramedFileSource::FramedFileSource(UsageEnvironment& env, FILE* fid) - : FramedSource(env), fFid(fid) { -} - -FramedFileSource::~FramedFileSource() { -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/FramedFilter.cpp b/mythtv/libs/libmythlivemedia/liveMedia/FramedFilter.cpp deleted file mode 100644 index baaf44181ef..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/FramedFilter.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Framed Filters -// Implementation - -#include "FramedFilter.hh" - -////////// FramedFilter ////////// -#include - -FramedFilter::FramedFilter(UsageEnvironment& env, - FramedSource* inputSource) - : FramedSource(env), - fInputSource(inputSource) { -} - -FramedFilter::~FramedFilter() { - Medium::close(fInputSource); -} - -// Default implementations of needed virtual functions. These merely -// call the same function in the input source - i.e., act like a 'null filter - -char const* FramedFilter::MIMEtype() const { - return fInputSource->MIMEtype(); -} - -void FramedFilter::getAttributes() const { - fInputSource->getAttributes(); -} - -void FramedFilter::doStopGettingFrames() { - fInputSource->stopGettingFrames(); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/FramedSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/FramedSource.cpp deleted file mode 100644 index 9b4ba30d788..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/FramedSource.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Framed Sources -// Implementation - -#include "FramedSource.hh" -#include - -////////// FramedSource ////////// - -FramedSource::FramedSource(UsageEnvironment& env) - : MediaSource(env), - fAfterGettingFunc(NULL), fAfterGettingClientData(NULL), - fOnCloseFunc(NULL), fOnCloseClientData(NULL), - fIsCurrentlyAwaitingData(False) { - fPresentationTime.tv_sec = fPresentationTime.tv_usec = 0; // initially -} - -FramedSource::~FramedSource() { -} - -Boolean FramedSource::isFramedSource() const { - return True; -} - -Boolean FramedSource::lookupByName(UsageEnvironment& env, char const* sourceName, - FramedSource*& resultSource) { - resultSource = NULL; // unless we succeed - - MediaSource* source; - if (!MediaSource::lookupByName(env, sourceName, source)) return False; - - if (!source->isFramedSource()) { - env.setResultMsg(sourceName, " is not a framed source"); - return False; - } - - resultSource = (FramedSource*)source; - return True; -} - -void FramedSource::getNextFrame(unsigned char* to, unsigned maxSize, - afterGettingFunc* afterGettingFunc, - void* afterGettingClientData, - onCloseFunc* onCloseFunc, - void* onCloseClientData) { - // Make sure we're not already being read: - if (fIsCurrentlyAwaitingData) { - envir() << "FramedSource[" << this << "]::getNextFrame(): attempting to read more than once at the same time!\n"; - exit(1); - } - - fTo = to; - fMaxSize = maxSize; - fNumTruncatedBytes = 0; // by default; could be changed by doGetNextFrame() - fDurationInMicroseconds = 0; // by default; could be changed by doGetNextFrame() - fAfterGettingFunc = afterGettingFunc; - fAfterGettingClientData = afterGettingClientData; - fOnCloseFunc = onCloseFunc; - fOnCloseClientData = onCloseClientData; - fIsCurrentlyAwaitingData = True; - - doGetNextFrame(); -} -// ##### The following is for backwards-compatibility; remove it eventually: -#ifdef BACKWARDS_COMPATIBLE_WITH_OLD_AFTER_GETTING_FUNC -static void bwCompatHackAfterGetting(void* clientData, unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - FramedSource* source = (FramedSource*)clientData; - FramedSource::bwCompatAfterGettingFunc* clientAfterGettingFunc - = source->fSavedBWCompatAfterGettingFunc; - void* afterGettingClientData = source->fSavedBWCompatAfterGettingClientData; - if (clientAfterGettingFunc != NULL) { - (*clientAfterGettingFunc)(afterGettingClientData, frameSize, presentationTime); - } -} -void FramedSource::getNextFrame(unsigned char* to, unsigned maxSize, - bwCompatAfterGettingFunc* afterGettingFunc, - void* afterGettingClientData, - onCloseFunc* onCloseFunc, - void* onCloseClientData) { - fSavedBWCompatAfterGettingFunc = afterGettingFunc; - fSavedBWCompatAfterGettingClientData = afterGettingClientData; - // Call the regular (new) "getNextFrame()": - getNextFrame(to, maxSize, bwCompatHackAfterGetting, this, - onCloseFunc, onCloseClientData); -} -#endif -// ##### End of code for backwards-compatibility. - -void FramedSource::afterGetting(FramedSource* source) { - source->fIsCurrentlyAwaitingData = False; - // indicates that we can be read again - // Note that this needs to be done here, in case the "fAfterFunc" - // called below tries to read another frame (which it usually will) - - if (source->fAfterGettingFunc != NULL) { - (*(source->fAfterGettingFunc))(source->fAfterGettingClientData, - source->fFrameSize, source->fNumTruncatedBytes, - source->fPresentationTime, - source->fDurationInMicroseconds); - } -} - -void FramedSource::handleClosure(void* clientData) { - FramedSource* source = (FramedSource*)clientData; - source->fIsCurrentlyAwaitingData = False; // because we got a close instead - if (source->fOnCloseFunc != NULL) { - (*(source->fOnCloseFunc))(source->fOnCloseClientData); - } -} - -void FramedSource::stopGettingFrames() { - fIsCurrentlyAwaitingData = False; // indicates that we can be read again - - // Perform any specialized action now: - doStopGettingFrames(); -} - -void FramedSource::doStopGettingFrames() { - // Default implementation: Do nothing - // Subclasses may wish to specialize this so as to ensure that a - // subsequent reader can pick up where this one left off. -} - -unsigned FramedSource::maxFrameSize() const { - // By default, this source has no maximum frame size. - return 0; -} - -Boolean FramedSource::isPrioritizedRTPStreamSelector() const { - return False; // default implementation -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/GSMAudioRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/GSMAudioRTPSink.cpp deleted file mode 100644 index c2e47989d99..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/GSMAudioRTPSink.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for GSM audio -// Implementation - -#include "GSMAudioRTPSink.hh" - -GSMAudioRTPSink::GSMAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs) - : AudioRTPSink(env, RTPgs, 3, 8000, "GSM") { -} - -GSMAudioRTPSink::~GSMAudioRTPSink() { -} - -GSMAudioRTPSink* -GSMAudioRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs) { - return new GSMAudioRTPSink(env, RTPgs); -} - -Boolean GSMAudioRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - // Allow at most 5 frames in a single packet: - return numFramesUsedSoFar() < 5; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/H261VideoRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/H261VideoRTPSource.cpp deleted file mode 100644 index ddf0f7a43ef..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/H261VideoRTPSource.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// H.261 Video RTP Sources -// Implementation - -#include "H261VideoRTPSource.hh" - -H261VideoRTPSource* -H261VideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new H261VideoRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -H261VideoRTPSource -::H261VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency), - fLastSpecialHeader(0) { -} - -H261VideoRTPSource::~H261VideoRTPSource() { -} - -Boolean H261VideoRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - // There's a 4-byte video-specific header - if (packet->dataSize() < 4) return False; - - unsigned char* headerStart = packet->data(); - fLastSpecialHeader - = (headerStart[0]<<24)|(headerStart[1]<<16)|(headerStart[2]<<8)|headerStart[3]; - -#ifdef DELIVER_COMPLETE_FRAMES - fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame; - // whether the *previous* packet ended a frame - - // The RTP "M" (marker) bit indicates the last fragment of a frame: - fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); -#endif - - resultSpecialHeaderSize = 4; - return True; -} - -char const* H261VideoRTPSource::MIMEtype() const { - return "video/H261"; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoFileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoFileServerMediaSubsession.cpp deleted file mode 100644 index c9197f23569..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoFileServerMediaSubsession.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a H263 video file. -// Implementation - -// Author: Bernhard Feiten. // Based on MPEG4VideoFileServerMediaSubsession - -#include "H263plusVideoFileServerMediaSubsession.hh" -#include "H263plusVideoRTPSink.hh" -#include "ByteStreamFileSource.hh" -#include "H263plusVideoStreamFramer.hh" - -//////////////////////////////////////////////////////////////////////////////// -H263plusVideoFileServerMediaSubsession* -H263plusVideoFileServerMediaSubsession::createNew( - UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource) { - return new H263plusVideoFileServerMediaSubsession(env, fileName, reuseFirstSource); -} - -//////////////////////////////////////////////////////////////////////////////// -H263plusVideoFileServerMediaSubsession::H263plusVideoFileServerMediaSubsession( - UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource) - : FileServerMediaSubsession(env, fileName, reuseFirstSource), - fDoneFlag(0) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -H263plusVideoFileServerMediaSubsession::~H263plusVideoFileServerMediaSubsession() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -#if 0 -static void afterPlayingDummy(void* clientData) { - H263plusVideoFileServerMediaSubsession* subsess - = (H263plusVideoFileServerMediaSubsession*)clientData; - // Signal the event loop that we're done: - subsess->setDoneFlag(); -} -#endif - -static void checkForAuxSDPLine(void* clientData) { - H263plusVideoFileServerMediaSubsession* subsess - = (H263plusVideoFileServerMediaSubsession*)clientData; - subsess->checkForAuxSDPLine1(); -} - -void H263plusVideoFileServerMediaSubsession::checkForAuxSDPLine1() { - if (fDummyRTPSink->auxSDPLine() != NULL) { - // Signal the event loop that we're done: - setDoneFlag(); - } else { - // try again after a brief delay: - int uSecsToDelay = 100000; // 100 ms - nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay, - (TaskFunc*)checkForAuxSDPLine, this); - } -} - -char const* H263plusVideoFileServerMediaSubsession::getAuxSDPLine( - RTPSink* rtpSink, - FramedSource* inputSource) -{ - // Note: For MPEG-4 video files, the 'config' information isn't known - // until we start reading the file. This means that "rtpSink"s - // "auxSDPLine()" will be NULL initially, and we need to start reading - // data from our file until this changes. - // Is this true also for H263 ?? >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - // asumption: no aux line needed for H263 - -// fDummyRTPSink = rtpSink; - - // Start reading the file: -// fDummyRTPSink->startPlaying(*inputSource, afterPlayingDummy, this); - - // Check whether the sink's 'auxSDPLine()' is ready: -// checkForAuxSDPLine(this); - -// envir().taskScheduler().doEventLoop(&fDoneFlag); - -// char const* auxSDPLine = fDummyRTPSink->auxSDPLine(); -// return auxSDPLine; - return NULL; -} - -//////////////////////////////////////////////////////////////////////////////// -FramedSource* H263plusVideoFileServerMediaSubsession::createNewStreamSource( - unsigned /*clientSessionId*/, - unsigned& estBitrate) -{ - estBitrate = 500; // kbps, estimate ?? - - // Create the video source: - ByteStreamFileSource* fileSource - = ByteStreamFileSource::createNew(envir(), fFileName); - if (fileSource == NULL) return NULL; - fFileSize = fileSource->fileSize(); - - // Create a framer for the Video Elementary Stream: - return H263plusVideoStreamFramer::createNew(envir(), fileSource); -} - -/////////////////////////////////////////////////////////////////////////////// -RTPSink* H263plusVideoFileServerMediaSubsession::createNewRTPSink( - Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* /*inputSource*/) -{ - unsigned char payloadFormatCode; - - if (false) // some more logic is needed if h263 is dynamic PT - payloadFormatCode = rtpPayloadTypeIfDynamic; - else - payloadFormatCode = 34; - - return H263plusVideoRTPSink::createNew(envir(), rtpGroupsock, payloadFormatCode); -} - - - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoRTPSink.cpp deleted file mode 100644 index 1e73276ca8d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoRTPSink.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for H.263+ video (RFC 2429) -// Implementation - -#include "H263plusVideoRTPSink.hh" - -H263plusVideoRTPSink -::H263plusVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency) - : VideoRTPSink(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, "H263-1998") { -} - -H263plusVideoRTPSink::~H263plusVideoRTPSink() { -} - -H263plusVideoRTPSink* -H263plusVideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency) { - return new H263plusVideoRTPSink(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency); -} - -Boolean H263plusVideoRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - // A packet can contain only one frame - return False; -} - -void H263plusVideoRTPSink -::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - if (fragmentationOffset == 0) { - // This packet contains the first (or only) fragment of the frame. - // Set the 'P' bit in the special header: - unsigned short specialHeader = 0x0400; - - // Also, reuse the first two bytes of the payload for this special - // header. (They should both have been zero.) - if (numBytesInFrame < 2) { - envir() << "H263plusVideoRTPSink::doSpecialFrameHandling(): bad frame size " - << numBytesInFrame << "\n"; - return; - } - if (frameStart[0] != 0 || frameStart[1] != 0) { - envir() << "H263plusVideoRTPSink::doSpecialFrameHandling(): unexpected non-zero first two bytes: " - << (void*)(frameStart[0]) << "," << (void*)(frameStart[1]) << "\n"; - } - frameStart[0] = specialHeader>>8; - frameStart[1] = (unsigned char)specialHeader; - } else { - unsigned short specialHeader = 0; - setSpecialHeaderBytes((unsigned char*)&specialHeader, 2); - } - - if (numRemainingBytes == 0) { - // This packet contains the last (or only) fragment of the frame. - // Set the RTP 'M' ('marker') bit: - setMarkerBit(); - } - - // Also set the RTP timestamp: - setTimestamp(frameTimestamp); -} - - -unsigned H263plusVideoRTPSink::specialHeaderSize() const { - // There's a 2-byte special video header. However, if we're the first - // (or only) fragment of a frame, then we reuse the first 2 bytes of - // the payload instead. - return (curFragmentationOffset() == 0) ? 0 : 2; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoRTPSource.cpp deleted file mode 100644 index 174f903b884..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoRTPSource.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// H.263+ Video RTP Sources -// Implementation - -#include "H263plusVideoRTPSource.hh" - -H263plusVideoRTPSource* -H263plusVideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new H263plusVideoRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -H263plusVideoRTPSource -::H263plusVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency), - fNumSpecialHeaders(0), fSpecialHeaderBytesLength(0) { -} - -H263plusVideoRTPSource::~H263plusVideoRTPSource() { -} - -Boolean H263plusVideoRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - unsigned char* headerStart = packet->data(); - unsigned packetSize = packet->dataSize(); - - // The H.263+ payload header is at least 2 bytes in size. - // Extract the known fields from the first 2 bytes: - unsigned expectedHeaderSize = 2; - if (packetSize < expectedHeaderSize) return False; - - //unsigned char RR = headerStart[0]>>3; - Boolean P = (headerStart[0]&0x4) != 0; - Boolean V = (headerStart[0]&0x2) != 0; - unsigned char PLEN = ((headerStart[0]&0x1)<<5)|(headerStart[1]>>3); - //unsigned char PEBIT = headerStart[1]&0x7; - - if (V) { - // There's an extra VRC byte at the end of the header: - ++expectedHeaderSize; - if (packetSize < expectedHeaderSize) return False; - } - - if (PLEN > 0) { - // There's an extra picture header at the end: - expectedHeaderSize += PLEN; - if (packetSize < expectedHeaderSize) return False; - } - - fCurrentPacketBeginsFrame = P; - if (fCurrentPacketBeginsFrame) { - fNumSpecialHeaders = fSpecialHeaderBytesLength = 0; - } - - // Make a copy of the special header bytes, in case a reader - // can use them: - unsigned bytesAvailable - = SPECIAL_HEADER_BUFFER_SIZE - fSpecialHeaderBytesLength - 1; - if (expectedHeaderSize <= bytesAvailable) { - fSpecialHeaderBytes[fSpecialHeaderBytesLength++] = expectedHeaderSize; - for (unsigned i = 0; i < expectedHeaderSize; ++i) { - fSpecialHeaderBytes[fSpecialHeaderBytesLength++] = headerStart[i]; - } - fPacketSizes[fNumSpecialHeaders++] = packetSize; - } - - if (P) { - // Prepend two zero bytes to the start of the payload proper. - // Hack: Do this by shrinking this special header by 2 bytes: - expectedHeaderSize -= 2; - headerStart[expectedHeaderSize] = 0; - headerStart[expectedHeaderSize+1] = 0; - } - - // The RTP "M" (marker) bit indicates the last fragment of a frame: - fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); - - resultSpecialHeaderSize = expectedHeaderSize; - return True; -} - -char const* H263plusVideoRTPSource::MIMEtype() const { - return "video/H263-1998"; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamFramer.cpp deleted file mode 100644 index dfe646585f2..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamFramer.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. -// Author Bernhard Feiten -// A filter that breaks up an H.263plus video stream into frames. -// - -#include "H263plusVideoStreamFramer.hh" -#include "H263plusVideoStreamParser.hh" - -#include -#include - - -/////////////////////////////////////////////////////////////////////////////// -////////// H263plusVideoStreamFramer implementation ////////// -//public/////////////////////////////////////////////////////////////////////// -H263plusVideoStreamFramer* H263plusVideoStreamFramer::createNew( - UsageEnvironment& env, - FramedSource* inputSource) -{ - // Need to add source type checking here??? ##### - H263plusVideoStreamFramer* fr; - fr = new H263plusVideoStreamFramer(env, inputSource); - return fr; -} - - -/////////////////////////////////////////////////////////////////////////////// -H263plusVideoStreamFramer::H263plusVideoStreamFramer( - UsageEnvironment& env, - FramedSource* inputSource, - Boolean createParser) - : FramedFilter(env, inputSource), - fFrameRate(0.0), // until we learn otherwise - fPictureEndMarker(False) -{ - // Use the current wallclock time as the base 'presentation time': - gettimeofday(&fPresentationTimeBase, NULL); - fParser = createParser ? new H263plusVideoStreamParser(this, inputSource) : NULL; -} - -/////////////////////////////////////////////////////////////////////////////// -H263plusVideoStreamFramer::~H263plusVideoStreamFramer() -{ - delete fParser; -} - - -/////////////////////////////////////////////////////////////////////////////// -#ifdef DEBUG -static struct timeval firstPT; -#endif - - -/////////////////////////////////////////////////////////////////////////////// -void H263plusVideoStreamFramer::doGetNextFrame() -{ - fParser->registerReadInterest(fTo, fMaxSize); - continueReadProcessing(); -} - - -/////////////////////////////////////////////////////////////////////////////// -Boolean H263plusVideoStreamFramer::isH263plusVideoStreamFramer() const -{ - return True; -} - -/////////////////////////////////////////////////////////////////////////////// -void H263plusVideoStreamFramer::continueReadProcessing( - void* clientData, - unsigned char* /*ptr*/, unsigned /*size*/, - struct timeval /*presentationTime*/) -{ - H263plusVideoStreamFramer* framer = (H263plusVideoStreamFramer*)clientData; - framer->continueReadProcessing(); -} - -/////////////////////////////////////////////////////////////////////////////// -void H263plusVideoStreamFramer::continueReadProcessing() -{ - unsigned acquiredFrameSize; - - u_int64_t frameDuration; // in ms - - acquiredFrameSize = fParser->parse(frameDuration); -// Calculate some average bitrate information (to be adapted) -// avgBitrate = (totalBytes * 8 * H263_TIMESCALE) / totalDuration; - - if (acquiredFrameSize > 0) { - // We were able to acquire a frame from the input. - // It has already been copied to the reader's space. - fFrameSize = acquiredFrameSize; -// fNumTruncatedBytes = fParser->numTruncatedBytes(); // not needed so far - - fFrameRate = frameDuration == 0 ? 0.0 : 1000./(long)frameDuration; - - // Compute "fPresentationTime" - if (acquiredFrameSize == 5) // first frame - fPresentationTime = fPresentationTimeBase; - else - fPresentationTime.tv_usec += (long) frameDuration*1000; - - while (fPresentationTime.tv_usec >= 1000000) { - fPresentationTime.tv_usec -= 1000000; - ++fPresentationTime.tv_sec; - } - - // Compute "fDurationInMicroseconds" - fDurationInMicroseconds = (unsigned int) frameDuration*1000;; - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); - } else { - // We were unable to parse a complete frame from the input, because: - // - we had to read more data from the source stream, or - // - the source stream has ended. - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamParser.cpp b/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamParser.cpp deleted file mode 100644 index d09cf1b121e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamParser.cpp +++ /dev/null @@ -1,857 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. -// Author Bernhard Feiten -// A filter that breaks up an H.263plus video stream into frames. -// Based on MPEG4IP/mp4creator/h263.c - -#include "H263plusVideoStreamParser.hh" -#include "H263plusVideoStreamFramer.hh" -//#include -//#include "GroupsockHelper.hh" - - -H263plusVideoStreamParser::H263plusVideoStreamParser( - H263plusVideoStreamFramer* usingSource, - FramedSource* inputSource) - : StreamParser(inputSource, - FramedSource::handleClosure, - usingSource, - &H263plusVideoStreamFramer::continueReadProcessing, - usingSource), - fUsingSource(usingSource), - fnextTR(0), - fcurrentPT(0) -{ - memset(fStates, 0, sizeof(fStates)); - memset(&fNextInfo, 0, sizeof(fNextInfo)); - memset(&fCurrentInfo, 0, sizeof(fCurrentInfo)); - memset(&fMaxBitrateCtx, 0, sizeof(fMaxBitrateCtx)); - memset(fNextHeader,0, H263_REQUIRE_HEADER_SIZE_BYTES); -} - -/////////////////////////////////////////////////////////////////////////////// -H263plusVideoStreamParser::~H263plusVideoStreamParser() -{ -} - -/////////////////////////////////////////////////////////////////////////////// -void H263plusVideoStreamParser::restoreSavedParserState() -{ - StreamParser::restoreSavedParserState(); - fTo = fSavedTo; - fNumTruncatedBytes = fSavedNumTruncatedBytes; -} - -/////////////////////////////////////////////////////////////////////////////// -void H263plusVideoStreamParser::setParseState() -{ - fSavedTo = fTo; - fSavedNumTruncatedBytes = fNumTruncatedBytes; - saveParserState(); // Needed for the parsing process in StreamParser -} - - -/////////////////////////////////////////////////////////////////////////////// -void H263plusVideoStreamParser::registerReadInterest( - unsigned char* to, - unsigned maxSize) -{ - fStartOfFrame = fTo = fSavedTo = to; - fLimit = to + maxSize; - fMaxSize = maxSize; - fNumTruncatedBytes = fSavedNumTruncatedBytes = 0; -} - -/////////////////////////////////////////////////////////////////////////////// -// parse() , derived from H263Creator of MPEG4IP, h263.c -unsigned H263plusVideoStreamParser::parse(u_int64_t & currentDuration) -{ - -// u_int8_t frameBuffer[H263_BUFFER_SIZE]; // The input buffer - // Pointer which tells LoadNextH263Object where to read data to -// u_int8_t* pFrameBuffer = fTo + H263_REQUIRE_HEADER_SIZE_BYTES; - u_int32_t frameSize; // The current frame size - // Pointer to receive address of the header data -// u_int8_t* pCurrentHeader;// = pFrameBuffer; -// u_int64_t currentDuration; // The current frame's duration - u_int8_t trDifference; // The current TR difference - // The previous TR difference -// u_int8_t prevTrDifference = H263_BASIC_FRAME_RATE; -// u_int64_t totalDuration = 0;// Duration accumulator -// u_int64_t avgBitrate; // Average bitrate -// u_int64_t totalBytes = 0; // Size accumulator - - - try // The get data routines of the class FramedFilter returns an error when - { // the buffer is empty. This occurs at the beginning and at the end of the file. - fCurrentInfo = fNextInfo; - - // Parse 1 frame - // For the first time, only the first frame's header is returned. - // The second time the full first frame is returned - frameSize = parseH263Frame(); - - currentDuration = 0; - if ((frameSize > 0)){ - // We were able to acquire a frame from the input. - - // Parse the returned frame header (if any) - if (!ParseShortHeader(fTo, &fNextInfo)) - ;// fprintf(stderr,"H263plusVideoStreamParser: Fatal error\n"); - trDifference = GetTRDifference(fNextInfo.tr, fCurrentInfo.tr); - - // calculate the current frame duration - currentDuration = CalculateDuration(trDifference); - - // Accumulate the frame's size and duration for avgBitrate calculation - //totalDuration += currentDuration; - //totalBytes += frameSize; - // If needed, recalculate bitrate information - // if (h263Bitrates) - //GetMaxBitrate(&fMaxBitrateCtx, frameSize, prevTrDifference); - //prevTrDifference = trDifference; - } - } catch (int /*e*/) { -#ifdef DEBUG - fprintf(stderr, "H263plusVideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n"); -#endif - frameSize=0; - } - - setParseState(); // Needed for the parsing process in StreamParser - - return frameSize; -} - - -/////////////////////////////////////////////////////////////////////////////// -// parseH263Frame derived from LoadNextH263Object of MPEG4IP -// - service routine that reads a single frame from the input file. -// It shall fill the input buffer with data up until - and including - the -// next start code and shall report back both the number of bytes read and a -// pointer to the next start code. The first call to this function shall only -// yield a pointer with 0 data bytes and the last call to this function shall -// only yield data bytes with a NULL pointer as the next header. -// -// TODO: This function only supports valid bit streams. Upon error, it fails -// without the possibility to recover. A Better idea would be to skip frames -// until a parsable frame is read from the file. -// -// Parameters: -// ppNextHeader - output parameter that upon return points to the location -// of the next frame's head in the buffer. -// This pointer shall be NULL for the last frame read. -// Returns the total number of bytes read. -// Uses FrameFileSource intantiated by constructor. -/////////////////////////////////////////////////////////////////////////////// -int H263plusVideoStreamParser::parseH263Frame( ) -{ - char row = 0; - u_int8_t * bufferIndex = fTo; - // The buffer end which will allow the loop to leave place for - // the additionalBytesNeeded - u_int8_t * bufferEnd = fTo + fMaxSize - ADDITIONAL_BYTES_NEEDED - 1; - - memcpy(fTo, fNextHeader, H263_REQUIRE_HEADER_SIZE_BYTES); - bufferIndex += H263_REQUIRE_HEADER_SIZE_BYTES; - - - // The state table and the following loop implements a state machine enabling - // us to read bytes from the file until (and inclusing) the requested - // start code (00 00 8X) is found - - // Initialize the states array, if it hasn't been initialized yet... - if (!fStates[0][0]) { - // One 00 was read - fStates[0][0] = 1; - // Two sequential 0x00 ware read - fStates[1][0] = fStates[2][0] = 2; - // A full start code was read - fStates[2][128] = fStates[2][129] = fStates[2][130] = fStates[2][131] = -1; - } - - // Read data from file into the output buffer until either a start code - // is found, or the end of file has been reached. - do { - *bufferIndex = get1Byte(); - } while ((bufferIndex < bufferEnd) && // We have place in the buffer - ((row = fStates[row][*(bufferIndex++)]) != -1)); // Start code was not found - - if (row != -1) { - fprintf(stderr, "%s: Buffer too small (%u)\n", - "h263reader:", bufferEnd - fTo + ADDITIONAL_BYTES_NEEDED); - return 0; - } - - // Cool ... now we have a start code - // Now we just have to read the additionalBytesNeeded - getBytes(bufferIndex, ADDITIONAL_BYTES_NEEDED); - memcpy(fNextHeader, bufferIndex - H263_STARTCODE_SIZE_BYTES, H263_REQUIRE_HEADER_SIZE_BYTES); - - int sz = bufferIndex - fTo - H263_STARTCODE_SIZE_BYTES; - - if (sz == 5) // first frame - memcpy(fTo, fTo+H263_REQUIRE_HEADER_SIZE_BYTES, H263_REQUIRE_HEADER_SIZE_BYTES); - - return sz; -} - - -//////////////////////////////////////////////////////////////////////////////// -// ParseShortHeader - service routine that accepts a buffer containing a frame -// header and extracts relevant codec information from it. -// -// NOTE: the first bit in the following commnets is 0 (zero). -// -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | PSC (Picture Start Code=22 bits) | (TR=8 bits) | > -// |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0| |1 0> -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// < (PTYPE=13 bits) | -// <. . .|(FMT)|Z|. . . .| -// +-+-+-+-+-+-+-+-+-+-+-+ -// -> PTYPE.FMT contains a width/height identification -// -> PTYPE.Z is 1 for P-Frames, 0 for I-Frames -// Note: When FMT is 111, there is an extended PTYPE... -// -// Inputs: -// headerBuffer - pointer to the current header buffer -// outputInfoStruct - pointer to the structure receiving the data -// Outputs: -// This function returns a structure of important codec-specific -// information (The Temporal Reference bits, width & height of the current -// frame and the sync - or "frame type" - bit. It reports success or -// failure to the calling function. -//////////////////////////////////////////////////////////////////////////////// -bool H263plusVideoStreamParser::ParseShortHeader( - u_int8_t *headerBuffer, - H263INFO *outputInfoStruct) -{ - u_int8_t fmt = 0; - // Extract temporal reference (TR) from the buffer (bits 22-29 inclusive) - outputInfoStruct->tr = (headerBuffer[2] << 6) & 0xC0; // 2 LS bits out of the 3rd byte - outputInfoStruct->tr |= (headerBuffer[3] >> 2) & 0x3F; // 6 MS bits out of the 4th byte - // Extract the FMT part of PTYPE from the buffer (bits 35-37 inclusive) - fmt = (headerBuffer[4] >> 2) & 0x07; // bits 3-5 ouf of the 5th byte - // If PTYPE is not supported, return a failure notice to the calling function - // FIXME: PLUSPTYPE is not supported - if (fmt == 0x07) { - return false; - } - // If PTYPE is supported, calculate the current width and height according to - // a predefined table - if (!GetWidthAndHeight(fmt, &(outputInfoStruct->width), - &(outputInfoStruct->height))) { - return false; - } - // Extract the frame-type bit, which is the 9th bit of PTYPE (bit 38) - outputInfoStruct->isSyncFrame = !(headerBuffer[4] & 0x02); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// GetMaxBitrate- service routine that accepts frame information and -// derives bitrate information from it. This function uses a sliding window -// technique to calculate the maximum bitrates in any window of 1 second -// inside the file. -// The sliding window is implemented with a table of bitrates for the last -// second (30 entries - one entry per TR unit). -// -// Inputs: -// ctx - context for this function -// frameSize - the size of the current frame in bytes -// frameTRDiff - the "duration" of the frame in TR units -// Outputs: -// This function returns the up-to-date maximum bitrate -//////////////////////////////////////////////////////////////////////////////// -void H263plusVideoStreamParser::GetMaxBitrate( MaxBitrate_CTX *ctx, - u_int32_t frameSize, - u_int8_t frameTRDiff) -{ - if (frameTRDiff == 0) - return; - - // Calculate the current frame's bitrate as bits per TR unit (round the result - // upwards) - u_int32_t frameBitrate = frameSize * 8 / frameTRDiff + 1; - - // for each TRdiff received, - while (frameTRDiff--) { - // Subtract the oldest bitrate entry from the current bitrate - ctx->windowBitrate -= ctx->bitrateTable[ctx->tableIndex]; - // Update the oldest bitrate entry with the current frame's bitrate - ctx->bitrateTable[ctx->tableIndex] = frameBitrate; - // Add the current frame's bitrate to the current bitrate - ctx->windowBitrate += frameBitrate; - // Check if we have a new maximum bitrate - if (ctx->windowBitrate > ctx->maxBitrate) { - ctx->maxBitrate = ctx->windowBitrate; - } - // Advance the table index - // Wrapping around the bitrateTable size - ctx->tableIndex = (ctx->tableIndex + 1) % - ( sizeof(ctx->bitrateTable) / sizeof(ctx->bitrateTable[0]) ); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// CalculateDuration - service routine that calculates the current frame's -// duration in milli-seconds using it's duration in TR units. -// - In order not to accumulate the calculation error, we are using the TR -// duration to calculate the current and the next frame's presentation time in -// milli-seconds. -// -// Inputs: trDiff - The current frame's duration in TR units -// Return: The current frame's duration in milli-seconds -//////////////////////////////////////////////////////////////////////////////// -u_int64_t H263plusVideoStreamParser::CalculateDuration(u_int8_t trDiff) -{ - //static u_int32_t nextTR = 0; // The next frame's presentation time in TR units - //static u_int64_t currentPT = 0; // The current frame's presentation time in milli-seconds - u_int64_t nextPT; // The next frame's presentation time in milli-seconds - u_int64_t duration; // The current frame's duration in milli-seconds - - fnextTR += trDiff; - // Calculate the next frame's presentation time, in milli-seconds - nextPT = (fnextTR * 1001) / H263_BASIC_FRAME_RATE; - // The frame's duration is the difference between the next presentation - // time and the current presentation time. - duration = nextPT - fcurrentPT; - // "Remember" the next presentation time for the next time this function is called - fcurrentPT = nextPT; - - return duration; -} - -//////////////////////////////////////////////////////////////////////////////// -bool H263plusVideoStreamParser::GetWidthAndHeight( u_int8_t fmt, - u_int16_t *width, - u_int16_t *height) -{ - // The 'fmt' corresponds to bits 5-7 of the PTYPE - static struct { - u_int16_t width; - u_int16_t height; - } dimensionsTable[8] = { - { 0, 0 }, // 000 - 0 - forbidden, generates an error - { 128, 96 }, // 001 - 1 - Sub QCIF - { 176, 144 }, // 010 - 2 - QCIF - { 352, 288 }, // 011 - 3 - CIF - { 704, 576 }, // 100 - 4 - 4CIF - { 1409, 1152 }, // 101 - 5 - 16CIF - { 0, 0 }, // 110 - 6 - reserved, generates an error - { 0, 0 } // 111 - 7 - extended, not supported by profile 0 - }; - - if (fmt > 7) - return false; - - *width = dimensionsTable[fmt].width; - *height = dimensionsTable[fmt].height; - - if (*width == 0) - return false; - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -u_int8_t H263plusVideoStreamParser::GetTRDifference( - u_int8_t nextTR, - u_int8_t currentTR) -{ - if (currentTR > nextTR) { - // Wrap around 255... - return nextTR + (256 - currentTR); - } else { - return nextTR - currentTR; - } -} - - - - - - - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -// this is the h263.c file of MPEG4IP mp4creator -/* -#include "mp4creator.h" - -// Default timescale for H.263 (1000ms) -#define H263_TIMESCALE 1000 -// Default H263 frame rate (30fps) -#define H263_BASIC_FRAME_RATE 30 - -// Minimum number of bytes needed to parse an H263 header -#define H263_REQUIRE_HEADER_SIZE_BYTES 5 -// Number of bytes the start code requries -#define H263_STARTCODE_SIZE_BYTES 3 -// This is the input buffer's size. It should contain -// 1 frame with the following start code -#define H263_BUFFER_SIZE 256 * 1024 -// The default max different (in %) betwqeen max and average bitrates -#define H263_DEFAULT_CBR_TOLERANCE 10 - -// The following structure holds information extracted from each frame's header: -typedef struct _H263INFO { - u_int8_t tr; // Temporal Reference, used in duration calculation - u_int16_t width; // Width of the picture - u_int16_t height; // Height of the picture - bool isSyncFrame; // Frame type (true = I frame = "sync" frame) -} H263INFO; - -// Context for the GetMaxBitrate function -typedef struct _MaxBitrate_CTX { - u_int32_t bitrateTable[H263_BASIC_FRAME_RATE];// Window of 1 second - u_int32_t windowBitrate; // The bitrate of the current window - u_int32_t maxBitrate; // The up-to-date maximum bitrate - u_int32_t tableIndex; // The next TR unit to update -} MaxBitrate_CTX; - -// Forward declarations: -static int LoadNextH263Object( FILE *inputFileHandle, - u_int8_t *frameBuffer, - u_int32_t *frameBufferSize, - u_int32_t additionalBytesNeeded, - u_int8_t **ppNextHeader); - -static bool ParseShortHeader( u_int8_t *headerBuffer, - H263INFO *outputInfoStruct); - -static u_int8_t GetTRDifference(u_int8_t nextTR, - u_int8_t currentTR); - -static void GetMaxBitrate( MaxBitrate_CTX *ctx, - u_int32_t frameSize, - u_int8_t frameTRDiff); - -static MP4Duration CalculateDuration(u_int8_t trDiff); - -static bool GetWidthAndHeight( u_int8_t fmt, - u_int16_t *width, - u_int16_t *height); - -static char states[3][256]; -/ * - * H263Creator - Main function - * Inputs: - * outputFileHandle - The handle of the output file - * inputFileHandle - The handle of the input file - * Codec-specific parameters: - * H263Level - H.263 Level used for this track - * H263Profile - H.263 Profile used for this track - * H263Bitrates - A Parameter indicating whether the function - * should calculate H263 bitrates or not. - * cbrTolerance - CBR tolerance indicates when to set the - * average bitrate. - * Outputs: - * This function returns either the track ID of the newly added track upon - * success or a predefined value representing an erroneous state. - * / -MP4TrackId H263Creator(MP4FileHandle outputFileHandle, - FILE* inputFileHandle, - u_int8_t h263Profile, - u_int8_t h263Level, - bool h263Bitrates, - u_int8_t cbrTolerance) -{ - H263INFO nextInfo; // Holds information about the next frame - H263INFO currentInfo;// Holds information about the current frame - MaxBitrate_CTX maxBitrateCtx;// Context for the GetMaxBitrate function - memset(&nextInfo, 0, sizeof(nextInfo)); - memset(¤tInfo, 0, sizeof(currentInfo)); - memset(&maxBitrateCtx, 0, sizeof(maxBitrateCtx)); - memset(states, 0, sizeof(states)); - u_int8_t frameBuffer[H263_BUFFER_SIZE]; // The input buffer - // Pointer which tells LoadNextH263Object where to read data to - u_int8_t* pFrameBuffer = frameBuffer + H263_REQUIRE_HEADER_SIZE_BYTES; - u_int32_t frameSize; // The current frame size - // Pointer to receive address of the header data - u_int8_t* pCurrentHeader = pFrameBuffer; - MP4Duration currentDuration; // The current frame's duration - u_int8_t trDifference; // The current TR difference - // The previous TR difference - u_int8_t prevTrDifference = H263_BASIC_FRAME_RATE; - MP4Duration totalDuration = 0;// Duration accumulator - MP4Duration avgBitrate; // Average bitrate - u_int64_t totalBytes = 0; // Size accumulator - MP4TrackId trackId = MP4_INVALID_TRACK_ID; // Our MP4 track - bool stay = true; // loop flag - - while (stay) { - currentInfo = nextInfo; - memmove(frameBuffer, pCurrentHeader, H263_REQUIRE_HEADER_SIZE_BYTES); - frameSize = H263_BUFFER_SIZE - H263_REQUIRE_HEADER_SIZE_BYTES; - // Read 1 frame and the next frame's header from the file. - // For the first frame, only the first frame's header is returned. - // For the last frame, only the last frame's data is returned. - if (! LoadNextH263Object(inputFileHandle, pFrameBuffer, &frameSize, - H263_REQUIRE_HEADER_SIZE_BYTES - H263_STARTCODE_SIZE_BYTES, - &pCurrentHeader)) - break; // Fatal error ... - - if (pCurrentHeader) { - // Parse the returned frame header (if any) - if (!ParseShortHeader(pCurrentHeader, &nextInfo)) - break; // Fatal error - trDifference = GetTRDifference(nextInfo.tr, currentInfo.tr); - } else { - // This is the last frame ... we have to fake the trDifference ... - trDifference = 1; - // No header data has been read at this iteration, so we have to manually - // add the frame's header we read at the previous iteration. - // Note that LoadNextH263Object returns the number of bytes read, which - // are the current frame's data and the next frame's header - frameSize += H263_REQUIRE_HEADER_SIZE_BYTES; - // There is no need for the next iteration ... - stay = false; - } - - // If this is the first iteration ... - if (currentInfo.width == 0) { - // If we have more data than just the header - if ((frameSize > H263_REQUIRE_HEADER_SIZE_BYTES) || - !pCurrentHeader) // Or no header at all - break; // Fatal error - else - continue; // We have only the first frame's header ... - } - - if (trackId == MP4_INVALID_TRACK_ID) { - // If a track has not been added yet, add the track to the file. - trackId = MP4AddH263VideoTrack(outputFileHandle, H263_TIMESCALE, - 0, currentInfo.width, currentInfo.height, - h263Level, h263Profile, 0, 0); - if (trackId == MP4_INVALID_TRACK_ID) - break; // Fatal error - } - - // calculate the current frame duration - currentDuration = CalculateDuration(trDifference); - // Write the current frame to the file. - if (!MP4WriteSample(outputFileHandle, trackId, frameBuffer, frameSize, - currentDuration, 0, currentInfo.isSyncFrame)) - break; // Fatal error - - // Accumulate the frame's size and duration for avgBitrate calculation - totalDuration += currentDuration; - totalBytes += frameSize; - // If needed, recalculate bitrate information - if (h263Bitrates) - GetMaxBitrate(&maxBitrateCtx, frameSize, prevTrDifference); - prevTrDifference = trDifference; - } // while (stay) - - // If this is the last frame, - if (!stay) { - // If needed and possible, update bitrate information in the file - if (h263Bitrates && totalDuration) { - avgBitrate = (totalBytes * 8 * H263_TIMESCALE) / totalDuration; - if (cbrTolerance == 0) - cbrTolerance = H263_DEFAULT_CBR_TOLERANCE; - // Same as: if (maxBitrate / avgBitrate > (cbrTolerance + 100) / 100.0) - if (maxBitrateCtx.maxBitrate * 100 > (cbrTolerance + 100) * avgBitrate) - avgBitrate = 0; - MP4SetH263Bitrates(outputFileHandle, trackId, - avgBitrate, maxBitrateCtx.maxBitrate); - } - // Return the newly added track ID - return trackId; - } - - // If we got to here... something went wrong ... - fprintf(stderr, - "%s: Could not parse input file, invalid video stream?\n", ProgName); - // Upon failure, delete the newly added track if it has been added - if (trackId != MP4_INVALID_TRACK_ID) { - MP4DeleteTrack(outputFileHandle, trackId); - } - return MP4_INVALID_TRACK_ID; -} - -/ * - * LoadNextH263Object - service routine that reads a single frame from the input - * file. It shall fill the input buffer with data up until - and including - the - * next start code and shall report back both the number of bytes read and a - * pointer to the next start code. The first call to this function shall only - * yield a pointer with 0 data bytes and the last call to this function shall - * only yield data bytes with a NULL pointer as the next header. - * - * TODO: This function only supports valid bit streams. Upon error, it fails - * without the possibility to recover. A Better idea would be to skip frames - * until a parsable frame is read from the file. - * - * Parameters: - * inputFileHandle - The handle of the input file - * frameBuffer - buffer where to place read data - * frameBufferSize - in/out parameter indicating the size of the buffer on - * entry and the number of bytes copied to the buffer upon - * return - * additionalBytesNeeded - indicates how many additional bytes are to be read - * from the next frame's header (over the 3 bytes that - * are already read). - * NOTE: This number MUST be > 0 - * ppNextHeader - output parameter that upon return points to the location - * of the next frame's head in the buffer - * Outputs: - * This function returns two pieces of information: - * 1. The total number of bytes read. - * 2. A Pointer to the header of the next frame. This pointer shall be NULL - * for the last frame read. - * / -static int LoadNextH263Object( FILE *inputFileHandle, - u_int8_t *frameBuffer, - u_int32_t *frameBufferSize, - u_int32_t additionalBytesNeeded, - u_int8_t **ppNextHeader) -{ - // This table and the following loop implements a state machine enabling - // us to read bytes from the file untill (and inclusing) the requested - // start code (00 00 8X) is found - int8_t row = 0; - u_int8_t *bufferStart = frameBuffer; - // The buffer end which will allow the loop to leave place for - // the additionalBytesNeeded - u_int8_t *bufferEnd = frameBuffer + *frameBufferSize - - additionalBytesNeeded - 1; - - // Initialize the states array, if it hasn't been initialized yet... - if (!states[0][0]) { - // One 00 was read - states[0][0] = 1; - // Two sequential 0x00 ware read - states[1][0] = states[2][0] = 2; - // A full start code was read - states[2][128] = states[2][129] = states[2][130] = states[2][131] = -1; - } - - // Read data from file into the output buffer until either a start code - // is found, or the end of file has been reached. - do { - if (fread(frameBuffer, 1, 1, inputFileHandle) != 1){ - // EOF or other error before we got a start code - *ppNextHeader = NULL; - *frameBufferSize = frameBuffer - bufferStart; - return 1; - } - } while ((frameBuffer < bufferEnd) && // We have place in the buffer - ((row = states[row][*(frameBuffer++)]) != -1)); // Start code was not found - if (row != -1) { - fprintf(stderr, "%s: Buffer too small (%u)\n", - ProgName, bufferEnd - bufferStart + additionalBytesNeeded); - return 0; - } - - // Cool ... now we have a start code - *ppNextHeader = frameBuffer - H263_STARTCODE_SIZE_BYTES; - *frameBufferSize = frameBuffer - bufferStart + additionalBytesNeeded; - - // Now we just have to read the additionalBytesNeeded - if(fread(frameBuffer, additionalBytesNeeded, 1, inputFileHandle) != 1) { - /// We got a start code but can't read additionalBytesNeeded ... that's a fatal error - fprintf(stderr, "%s: Invalid H263 bitstream\n", ProgName); - return 0; - } - - return 1; -} - - -/ * - * ParseShortHeader - service routine that accepts a buffer containing a frame - * header and extracts relevant codec information from it. - * - * NOTE: the first bit in the following commnets is 0 (zero). - * - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | PSC (Picture Start Code=22 bits) | (TR=8 bits) | > - * |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0| |1 0> - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * < (PTYPE=13 bits) | - * <. . .|(FMT)|Z|. . . .| - * +-+-+-+-+-+-+-+-+-+-+-+ - * -> PTYPE.FMT contains a width/height identification - * -> PTYPE.Z is 1 for P-Frames, 0 for I-Frames - * Note: When FMT is 111, there is an extended PTYPE... - * - * Inputs: - * headerBuffer - pointer to the current header buffer - * outputInfoStruct - pointer to the structure receiving the data - * Outputs: - * This function returns a structure of important codec-specific - * information (The Temporal Reference bits, width & height of the current - * frame and the sync - or "frame type" - bit. It reports success or - * failure to the calling function. - * / -static bool ParseShortHeader( u_int8_t *headerBuffer, - H263INFO *outputInfoStruct) -{ - u_int8_t fmt = 0; - // Extract temporal reference (TR) from the buffer (bits 22-29 inclusive) - outputInfoStruct->tr = (headerBuffer[2] << 6) & 0xC0; // 2 LS bits out of the 3rd byte - outputInfoStruct->tr |= (headerBuffer[3] >> 2) & 0x3F; // 6 MS bits out of the 4th byte - // Extract the FMT part of PTYPE from the buffer (bits 35-37 inclusive) - fmt = (headerBuffer[4] >> 2) & 0x07; // bits 3-5 ouf of the 5th byte - // If PTYPE is not supported, return a failure notice to the calling function - // FIXME: PLUSPTYPE is not supported - if (fmt == 0x07) { - return false; - } - // If PTYPE is supported, calculate the current width and height according to - // a predefined table - if (!GetWidthAndHeight(fmt, &(outputInfoStruct->width), - &(outputInfoStruct->height))) { - return false; - } - // Extract the frame-type bit, which is the 9th bit of PTYPE (bit 38) - outputInfoStruct->isSyncFrame = !(headerBuffer[4] & 0x02); - - return true; -} - -/ * - * GetMaxBitrate- service routine that accepts frame information and - * derives bitrate information from it. This function uses a sliding window - * technique to calculate the maximum bitrates in any window of 1 second - * inside the file. - * The sliding window is implemented with a table of bitrates for the last - * second (30 entries - one entry per TR unit). - * - * Inputs: - * ctx - context for this function - * frameSize - the size of the current frame in bytes - * frameTRDiff - the "duration" of the frame in TR units - * Outputs: - * This function returns the up-to-date maximum bitrate - * / -static void GetMaxBitrate( MaxBitrate_CTX *ctx, - u_int32_t frameSize, - u_int8_t frameTRDiff) -{ - if (frameTRDiff == 0) - return; - - // Calculate the current frame's bitrate as bits per TR unit (round the result - // upwards) - u_int32_t frameBitrate = frameSize * 8 / frameTRDiff + 1; - - // for each TRdiff received, - while (frameTRDiff--) { - // Subtract the oldest bitrate entry from the current bitrate - ctx->windowBitrate -= ctx->bitrateTable[ctx->tableIndex]; - // Update the oldest bitrate entry with the current frame's bitrate - ctx->bitrateTable[ctx->tableIndex] = frameBitrate; - // Add the current frame's bitrate to the current bitrate - ctx->windowBitrate += frameBitrate; - // Check if we have a new maximum bitrate - if (ctx->windowBitrate > ctx->maxBitrate) { - ctx->maxBitrate = ctx->windowBitrate; - } - // Advance the table index - ctx->tableIndex = (ctx->tableIndex + 1) % - // Wrapping around the bitrateTable size - ( sizeof(ctx->bitrateTable) / sizeof(ctx->bitrateTable[0]) ); - } -} - -/ * - * CalculateDuration - service routine that calculates the current frame's - * duration in milli-seconds using it's duration in TR units. - * - In order not to accumulate the calculation error, we are using the TR - * duration to calculate the current and the next frame's presentation time in - * milli-seconds. - * - * Inputs: - * trDiff - The current frame's duration in TR units - * Outputs: - * The current frame's duration in milli-seconds - * / -static MP4Duration CalculateDuration(u_int8_t trDiff) -{ - static u_int32_t nextTR = 0; // The next frame's presentation time in TR units - static MP4Duration currentPT = 0; // The current frame's presentation time in milli-seconds - MP4Duration nextPT; // The next frame's presentation time in milli-seconds - MP4Duration duration; // The current frame's duration in milli-seconds - - nextTR += trDiff; - // Calculate the next frame's presentation time, in milli-seconds - nextPT = (nextTR * 1001) / H263_BASIC_FRAME_RATE; - // The frame's duration is the difference between the next presentation - // time and the current presentation time. - duration = nextPT - currentPT; - // "Remember" the next presentation time for the next time this function is - // called - currentPT = nextPT; - - return duration; -} - -static bool GetWidthAndHeight( u_int8_t fmt, - u_int16_t *width, - u_int16_t *height) -{ - // The 'fmt' corresponds to bits 5-7 of the PTYPE - static struct { - u_int16_t width; - u_int16_t height; - } dimensionsTable[8] = { - { 0, 0 }, // 000 - 0 - forbidden, generates an error - { 128, 96 }, // 001 - 1 - Sub QCIF - { 176, 144 }, // 010 - 2 - QCIF - { 352, 288 }, // 011 - 3 - CIF - { 704, 576 }, // 100 - 4 - 4CIF - { 1409, 1152 }, // 101 - 5 - 16CIF - { 0, 0 }, // 110 - 6 - reserved, generates an error - { 0, 0 } // 111 - 7 - extended, not supported by profile 0 - }; - - if (fmt > 7) - return false; - - *width = dimensionsTable[fmt].width; - *height = dimensionsTable[fmt].height; - - if (*width == 0) - return false; - - return true; -} - -static u_int8_t GetTRDifference(u_int8_t nextTR, - u_int8_t currentTR) -{ - if (currentTR > nextTR) { - // Wrap around 255... - return nextTR + (256 - currentTR); - } else { - return nextTR - currentTR; - } -} - -*/ - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamParser.hh b/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamParser.hh deleted file mode 100644 index 23944d9fe0b..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/H263plusVideoStreamParser.hh +++ /dev/null @@ -1,127 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. -// A filter that breaks up an H263 video stream into frames. -// derived from MPEG4IP h263.c -// Author Benhard Feiten - -#ifndef _H263PLUS_VIDEO_STREAM_PARSER_HH -#define _H263PLUS_VIDEO_STREAM_PARSER_HH - -#ifndef _STREAM_PARSER_HH -#include "StreamParser.hh" -#endif - - -// Default timescale for H.263 (1000ms) -#define H263_TIMESCALE 1000 - -// Default H263 frame rate (30fps) -#define H263_BASIC_FRAME_RATE 30 - -// Minimum number of bytes needed to parse an H263 header -#define H263_REQUIRE_HEADER_SIZE_BYTES 5 - -// Number of bytes the start code requries -#define H263_STARTCODE_SIZE_BYTES 3 - -// This is the input buffer's size. It should contain -// 1 frame with the following start code -#define H263_BUFFER_SIZE 256 * 1024 - -// additionalBytesNeeded - indicates how many additional bytes are to be read -// from the next frame's header (over the 3 bytes that are already read). -#define ADDITIONAL_BYTES_NEEDED H263_REQUIRE_HEADER_SIZE_BYTES - H263_STARTCODE_SIZE_BYTES - -// The default max different (in %) betwqeen max and average bitrates -#define H263_DEFAULT_CBR_TOLERANCE 10 - - - -// The following structure holds information extracted from each frame's header: -typedef struct _H263INFO { - u_int8_t tr; // Temporal Reference, used in duration calculation - u_int16_t width; // Width of the picture - u_int16_t height; // Height of the picture - bool isSyncFrame; // Frame type (true = I frame = "sync" frame) -} H263INFO; - -typedef struct _MaxBitrate_CTX { - u_int32_t bitrateTable[H263_BASIC_FRAME_RATE];// Window of 1 second - u_int32_t windowBitrate; // The bitrate of the current window - u_int32_t maxBitrate; // The up-to-date maximum bitrate - u_int32_t tableIndex; // The next TR unit to update -} MaxBitrate_CTX; - - -class H263plusVideoStreamParser : public StreamParser { - -public: - H263plusVideoStreamParser( class H263plusVideoStreamFramer* usingSource, - FramedSource* inputSource); - - virtual ~H263plusVideoStreamParser(); - - void registerReadInterest(unsigned char* to, unsigned maxSize); - - unsigned parse(u_int64_t & currentDuration); // returns the size of the frame that was acquired, or 0 if none - unsigned numTruncatedBytes() const { return fNumTruncatedBytes; } // The number of truncated bytes (if any) - - -protected: -// H263plusVideoStreamFramer* usingSource() { -// return (H263plusVideoStreamFramer*)fUsingSource; -// } - void setParseState(); - -// void setParseState(H263plusParseState parseState); - - -private: - int parseH263Frame( ); - bool ParseShortHeader(u_int8_t *headerBuffer, H263INFO *outputInfoStruct); - void GetMaxBitrate( MaxBitrate_CTX *ctx, u_int32_t frameSize, u_int8_t frameTRDiff); - u_int64_t CalculateDuration(u_int8_t trDiff); - bool GetWidthAndHeight( u_int8_t fmt, u_int16_t *width, u_int16_t *height); - u_int8_t GetTRDifference( u_int8_t nextTR, u_int8_t currentTR); - - virtual void restoreSavedParserState(); - -protected: - class H263plusVideoStreamFramer* fUsingSource; - - unsigned char* fTo; - unsigned fMaxSize; - unsigned char* fStartOfFrame; - unsigned char* fSavedTo; - unsigned char* fLimit; - unsigned fNumTruncatedBytes; - unsigned fSavedNumTruncatedBytes; - -private: - H263INFO fNextInfo; // Holds information about the next frame - H263INFO fCurrentInfo; // Holds information about the current frame - MaxBitrate_CTX fMaxBitrateCtx; // Context for the GetMaxBitrate function - char fStates[3][256]; - u_int8_t fNextHeader[H263_REQUIRE_HEADER_SIZE_BYTES]; - - u_int32_t fnextTR; // The next frame's presentation time in TR units - u_int64_t fcurrentPT; // The current frame's presentation time in milli-seconds - -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/H264VideoRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/H264VideoRTPSource.cpp deleted file mode 100644 index 7963f061087..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/H264VideoRTPSource.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// H.264 Video RTP Sources -// Implementation - -#include "H264VideoRTPSource.hh" -#include "Base64.hh" - -////////// H264BufferedPacket and H264BufferedPacketFactory ////////// - -class H264BufferedPacket: public BufferedPacket { -public: - H264BufferedPacket(H264VideoRTPSource& ourSource); - virtual ~H264BufferedPacket(); - -private: // redefined virtual functions - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); -private: - H264VideoRTPSource& fOurSource; -}; - -class H264BufferedPacketFactory: public BufferedPacketFactory { -private: // redefined virtual functions - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - - -///////// MPEG4H264VideoRTPSource implementation //////// - -H264VideoRTPSource* -H264VideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new H264VideoRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -H264VideoRTPSource -::H264VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, - new H264BufferedPacketFactory) { -} - -H264VideoRTPSource::~H264VideoRTPSource() { -} - -Boolean H264VideoRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - unsigned char* headerStart = packet->data(); - unsigned packetSize = packet->dataSize(); - - // The header has a minimum size of 0, since the NAL header is used - // as a payload header - unsigned expectedHeaderSize = 0; - - // Check if the type field is 28 (FU-A) or 29 (FU-B) - fCurPacketNALUnitType = (headerStart[0]&0x1F); - switch (fCurPacketNALUnitType) { - case 24: { // STAP-A - expectedHeaderSize = 1; // discard the type byte - break; - } - case 25: case 26: case 27: { // STAP-B, MTAP16, or MTAP24 - expectedHeaderSize = 3; // discard the type byte, and the initial DON - break; - } - case 28: case 29: { // // FU-A or FU-B - // For these NALUs, the first two bytes are the FU indicator and the FU header. - // If the start bit is set, we reconstruct the original NAL header: - unsigned char startBit = headerStart[1]&0x80; - unsigned char endBit = headerStart[1]&0x40; - if (startBit) { - expectedHeaderSize = 1; - if (packetSize < expectedHeaderSize) return False; - - headerStart[1] = (headerStart[0]&0xE0)+(headerStart[1]&0x1F); - fCurrentPacketBeginsFrame = True; - } else { - // If the startbit is not set, both the FU indicator and header - // can be discarded - expectedHeaderSize = 2; - if (packetSize < expectedHeaderSize) return False; - fCurrentPacketBeginsFrame = False; - } - fCurrentPacketCompletesFrame = (endBit != 0); - break; - } - default: { - // This packet contains one or more complete, decodable NAL units - fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame = True; - break; - } - } - - resultSpecialHeaderSize = expectedHeaderSize; - return True; -} - -char const* H264VideoRTPSource::MIMEtype() const { - return "video/H264"; -} - -SPropRecord* parseSPropParameterSets(char const* sPropParameterSetsStr, - // result parameter: - unsigned& numSPropRecords) { - // Make a copy of the input string, so we can replace the commas with '\0's: - char* inStr = strDup(sPropParameterSetsStr); - if (inStr == NULL) { - numSPropRecords = 0; - return NULL; - } - - // Count the number of commas (and thus the number of parameter sets): - numSPropRecords = 1; - char* s; - for (s = inStr; *s != '\0'; ++s) { - if (*s == ',') { - ++numSPropRecords; - *s = '\0'; - } - } - - // Allocate and fill in the result array: - SPropRecord* resultArray = new SPropRecord[numSPropRecords]; - s = inStr; - for (unsigned i = 0; i < numSPropRecords; ++i) { - resultArray[i].sPropBytes = base64Decode(s, resultArray[i].sPropLength); - s += strlen(s) + 1; - } - - delete[] inStr; - return resultArray; -} - - -////////// H264BufferedPacket and H264BufferedPacketFactory implementation ////////// - -H264BufferedPacket::H264BufferedPacket(H264VideoRTPSource& ourSource) - : fOurSource(ourSource) { -} - -H264BufferedPacket::~H264BufferedPacket() { -} - -unsigned H264BufferedPacket -::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { - unsigned resultNALUSize = 0; // if an error occurs - - switch (fOurSource.fCurPacketNALUnitType) { - case 24: case 25: { // STAP-A or STAP-B - // The first two bytes are NALU size: - if (dataSize < 2) break; - resultNALUSize = (framePtr[0]<<8)|framePtr[1]; - framePtr += 2; - break; - } - case 26: { // MTAP16 - // The first two bytes are NALU size. The next three are the DOND and TS offset: - if (dataSize < 5) break; - resultNALUSize = (framePtr[0]<<8)|framePtr[1]; - framePtr += 5; - break; - } - case 27: { // MTAP24 - // The first two bytes are NALU size. The next four are the DOND and TS offset: - if (dataSize < 6) break; - resultNALUSize = (framePtr[0]<<8)|framePtr[1]; - framePtr += 6; - break; - } - default: { - // Common case: We use the entire packet data: - return dataSize; - } - } - - return (resultNALUSize <= dataSize) ? resultNALUSize : dataSize; -} - -BufferedPacket* H264BufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* ourSource) { - return new H264BufferedPacket((H264VideoRTPSource&)(*ourSource)); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/HTTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/HTTPSink.cpp deleted file mode 100644 index d31adf2fd04..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/HTTPSink.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// HTTP sinks -// Implementation - -#include "HTTPSink.hh" -#include "GroupsockHelper.hh" - -#include -#if defined(__WIN32__) || defined(_WIN32) -#define snprintf _snprintf -#endif - -////////// HTTPSink ////////// - -HTTPSink* HTTPSink::createNew(UsageEnvironment& env, Port ourPort) { - int ourSocket = -1; - - do { - int ourSocket = setUpOurSocket(env, ourPort); - if (ourSocket == -1) break; - - HTTPSink* newSink = new HTTPSink(env, ourSocket); - if (newSink == NULL) break; - - appendPortNum(env, ourPort); - - return newSink; - } while (0); - - if (ourSocket != -1) ::closeSocket(ourSocket); - return NULL; -} - -int HTTPSink::setUpOurSocket(UsageEnvironment& env, Port& ourPort) { - int ourSocket = -1; - - do { - ourSocket = setupStreamSocket(env, ourPort); - if (ourSocket < 0) break; - - // Make sure we have a big send buffer: - if (!increaseSendBufferTo(env, ourSocket, 50*1024)) break; - - if (listen(ourSocket, 1) < 0) { // we allow only one connection - env.setResultErrMsg("listen() failed: "); - break; - } - - if (ourPort.num() == 0) { - // bind() will have chosen a port for us; return it also: - if (!getSourcePort(env, ourSocket, ourPort)) break; - } - - return ourSocket; - } while (0); - - if (ourSocket != -1) ::closeSocket(ourSocket); - return -1; -} - -void HTTPSink::appendPortNum(UsageEnvironment& env, - Port const& port) { - char tmpBuf[10]; // large enough to hold a port # string - sprintf(tmpBuf, " %d", ntohs(port.num())); - env.appendToResultMsg(tmpBuf); -} - - -HTTPSink::HTTPSink(UsageEnvironment& env, int ourSocket) - : MediaSink(env), fSocket(ourSocket), fClientSocket(-1) { -} - -HTTPSink::~HTTPSink() { - ::closeSocket(fSocket); -} - - Boolean HTTPSink::isUseableFrame(unsigned char* /*framePtr*/, - unsigned /*frameSize*/) { - // default implementation - return True; -} - -Boolean HTTPSink::continuePlaying() { - if (fSource == NULL) return False; - - if (fClientSocket < 0) { - // We're still waiting for a connection from a client. - // Try making one now. (Recall that we're non-blocking) - struct sockaddr_in clientAddr; - SOCKLEN_T clientAddrLen = sizeof clientAddr; - fClientSocket = accept(fSocket, (struct sockaddr*)&clientAddr, - &clientAddrLen); - if (fClientSocket < 0) { - int err = envir().getErrno(); - if (err != EWOULDBLOCK) { - envir().setResultErrMsg("accept() failed: "); - return False; - } - } else { - // We made a connection; so send back a HTTP "OK", followed by other - // information (in particular, "Content-Type:") that will make - // client player tools happy: - char okResponse[400]; - const char* responseFmt = "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nContent-Length: 2147483647\r\nContent-Type: %s\r\n\r\n"; -#if defined(IRIX) || defined(ALPHA) || defined(_QNX4) || defined(IMN_PIM) || defined(CRIS) || defined (VXWORKS) - /* snprintf() isn't defined, so just use sprintf() - ugh! */ - sprintf(okResponse, responseFmt, fSource->MIMEtype()); -#else - snprintf(okResponse, sizeof okResponse, responseFmt, fSource->MIMEtype()); -#endif - send(fClientSocket, okResponse, strlen(okResponse), 0); - } - } - - fSource->getNextFrame(fBuffer, sizeof fBuffer, - afterGettingFrame, this, - ourOnSourceClosure, this); - - return True; -} - -void HTTPSink::ourOnSourceClosure(void* clientData) { - // No more input frames - we're done: - HTTPSink* sink = (HTTPSink*) clientData; - ::closeSocket(sink->fClientSocket); - sink->fClientSocket = -1; - onSourceClosure(sink); -} - -void HTTPSink::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - HTTPSink* sink = (HTTPSink*)clientData; - sink->afterGettingFrame1(frameSize, presentationTime); -} - -void HTTPSink::afterGettingFrame1(unsigned frameSize, - struct timeval /*presentationTime*/) { - // Write the data back to our client socket (if we have one): - if (fClientSocket >= 0 && isUseableFrame(fBuffer, frameSize)) { - int sendResult - = send(fClientSocket, (char*)(&fBuffer[0]), frameSize, 0); - if (sendResult < 0) { - int err = envir().getErrno(); - if (err != EWOULDBLOCK) { - // The client appears to have gone; close him down, - // and consider ourselves done: - ourOnSourceClosure(this); - return; - } - } - } - - // Then try getting the next frame: - continuePlaying(); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/InputFile.cpp b/mythtv/libs/libmythlivemedia/liveMedia/InputFile.cpp deleted file mode 100644 index 10947ce04ae..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/InputFile.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Common routines for opening/closing named input files -// Implementation - -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE) -#include -#include -#endif -#ifndef _WIN32_WCE -#include -#endif -#include - -#include "InputFile.hh" - -FILE* OpenInputFile(UsageEnvironment& env, char const* fileName) { - FILE* fid; - - // Check for a special case file name: "stdin" - if (strcmp(fileName, "stdin") == 0) { - fid = stdin; -#if defined(__WIN32__) || defined(_WIN32) - _setmode(_fileno(stdin), _O_BINARY); // convert to binary mode -#endif - } else { - fid = fopen(fileName, "rb"); - if (fid == NULL) { - env.setResultMsg("unable to open file \"",fileName, "\""); - } - } - - return fid; -} - -void CloseInputFile(FILE* fid) { - // Don't close 'stdin', in case we want to use it again later. - if (fid != NULL && fid != stdin) fclose(fid); -} - -u_int64_t GetFileSize(char const* fileName, FILE* fid) { - u_int64_t fileSize = 0; // by default - - if (fid != stdin) { -#if !defined(_WIN32_WCE) - if (fileName == NULL) { -#endif - if (SeekFile64(fid, 0, SEEK_END) >= 0) { - fileSize = TellFile64(fid); - if (fileSize == (u_int64_t)-1) fileSize = 0; // TellFile64() failed - SeekFile64(fid, 0, SEEK_SET); - } -#if !defined(_WIN32_WCE) - } else { - struct stat sb; - if (stat(fileName, &sb) == 0) { - fileSize = sb.st_size; - } - } -#endif - } - - return fileSize; -} - -u_int64_t SeekFile64(FILE *fid, int64_t offset, int whence) { - clearerr(fid); - fflush(fid); -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE) - return _lseeki64(_fileno(fid), offset, whence) == (int64_t)-1 ? -1 : 0; -#else -#if defined(_WIN32_WCE) - return fseek(fid, (long)(offset), whence); -#else - return fseeko(fid, (off_t)(offset), whence); -#endif -#endif -} - -u_int64_t TellFile64(FILE *fid) { - clearerr(fid); - fflush(fid); -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE) - return _telli64(_fileno(fid)); -#else -#if defined(_WIN32_WCE) - return ftell(fid); -#else - return ftello(fid); -#endif -#endif -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoRTPSink.cpp deleted file mode 100644 index 12e59472fd9..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoRTPSink.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for JPEG video (RFC 2435) -// Implementation - -#include "JPEGVideoRTPSink.hh" -#include "JPEGVideoSource.hh" - -JPEGVideoRTPSink -::JPEGVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs) - : VideoRTPSink(env, RTPgs, 26, 90000, "JPEG") { -} - -JPEGVideoRTPSink::~JPEGVideoRTPSink() { -} - -JPEGVideoRTPSink* -JPEGVideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs) { - return new JPEGVideoRTPSink(env, RTPgs); -} - -Boolean JPEGVideoRTPSink::sourceIsCompatibleWithUs(MediaSource& source) { - return source.isJPEGVideoSource(); -} - -Boolean JPEGVideoRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - // A packet can contain only one frame - return False; -} - -void JPEGVideoRTPSink -::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* /*frameStart*/, - unsigned /*numBytesInFrame*/, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - // Our source is known to be a JPEGVideoSource - JPEGVideoSource* source = (JPEGVideoSource*)fSource; - - u_int8_t mainJPEGHeader[8]; // the special header - - mainJPEGHeader[0] = 0; // Type-specific - mainJPEGHeader[1] = fragmentationOffset >> 16; - mainJPEGHeader[2] = fragmentationOffset >> 8; - mainJPEGHeader[3] = fragmentationOffset; - mainJPEGHeader[4] = source->type(); - mainJPEGHeader[5] = source->qFactor(); - mainJPEGHeader[6] = source->width(); - mainJPEGHeader[7] = source->height(); - setSpecialHeaderBytes(mainJPEGHeader, sizeof mainJPEGHeader); - - if (fragmentationOffset == 0 && source->qFactor() >= 128) { - // There is also a Quantization Header: - u_int8_t precision; - u_int16_t length; - u_int8_t const* quantizationTables - = source->quantizationTables(precision, length); - - unsigned const quantizationHeaderSize = 4 + length; - u_int8_t* quantizationHeader = new u_int8_t[quantizationHeaderSize]; - - quantizationHeader[0] = 0; // MBZ - quantizationHeader[1] = precision; - quantizationHeader[2] = length >> 8; - quantizationHeader[3] = length&0xFF; - if (quantizationTables != NULL) { // sanity check - for (u_int16_t i = 0; i < length; ++i) { - quantizationHeader[4+i] = quantizationTables[i]; - } - } - - setSpecialHeaderBytes(quantizationHeader, quantizationHeaderSize, - sizeof mainJPEGHeader /* start position */); - delete[] quantizationHeader; - } - - if (numRemainingBytes == 0) { - // This packet contains the last (or only) fragment of the frame. - // Set the RTP 'M' ('marker') bit: - setMarkerBit(); - } - - // Also set the RTP timestamp: - setTimestamp(frameTimestamp); -} - - -unsigned JPEGVideoRTPSink::specialHeaderSize() const { - // Our source is known to be a JPEGVideoSource - JPEGVideoSource* source = (JPEGVideoSource*)fSource; - - unsigned headerSize = 8; // by default - - if (curFragmentationOffset() == 0 && source->qFactor() >= 128) { - // There is also a Quantization Header: - u_int8_t dummy; - u_int16_t quantizationTablesSize; - (void)(source->quantizationTables(dummy, quantizationTablesSize)); - - headerSize += 4 + quantizationTablesSize; - } - - // Note: We assume that there are no 'restart markers' - - return headerSize; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoRTPSource.cpp deleted file mode 100644 index 6153438eec8..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoRTPSource.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. - -// JPEG Video (RFC 2435) RTP Sources -// Implementation -// 09 26 2002 - Initial Implementation : Giom -// Copyright (c) 1990-2002 Morgan Multimedia All rights reserved. - -// 02/2003: Cleaned up to add the synthesized JPEG header to the start -// of each incoming frame. -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. - -#include "JPEGVideoRTPSource.hh" - -////////// JPEGBufferedPacket and JPEGBufferedPacketFactory ////////// - -class JPEGBufferedPacket: public BufferedPacket { -public: - Boolean completesFrame; - -private: - // Redefined virtual functions: - virtual void reset(); - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); -}; - -class JPEGBufferedPacketFactory: public BufferedPacketFactory { -private: // redefined virtual functions - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - - -////////// JPEGVideoRTPSource implementation ////////// - -#define BYTE unsigned char -#define WORD unsigned -#define DWORD unsigned long - -JPEGVideoRTPSource* -JPEGVideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new JPEGVideoRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -JPEGVideoRTPSource::JPEGVideoRTPSource(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency, - new JPEGBufferedPacketFactory) { -} - -JPEGVideoRTPSource::~JPEGVideoRTPSource() { -} - -enum { - MARKER_SOF0 = 0xc0, // start-of-frame, baseline scan - MARKER_SOI = 0xd8, // start of image - MARKER_EOI = 0xd9, // end of image - MARKER_SOS = 0xda, // start of scan - MARKER_DRI = 0xdd, // restart interval - MARKER_DQT = 0xdb, // define quantization tables - MARKER_DHT = 0xc4, // huffman tables - MARKER_APP_FIRST = 0xe0, - MARKER_APP_LAST = 0xef, - MARKER_COMMENT = 0xfe, -}; - -static unsigned char const lum_dc_codelens[] = { - 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -}; - -static unsigned char const lum_dc_symbols[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -}; - -static unsigned char const lum_ac_codelens[] = { - 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d, -}; - -static unsigned char const lum_ac_symbols[] = { - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, -}; - -static unsigned char const chm_dc_codelens[] = { - 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, -}; - -static unsigned char const chm_dc_symbols[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -}; - -static unsigned char const chm_ac_codelens[] = { - 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77, -}; - -static unsigned char const chm_ac_symbols[] = { - 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, - 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, - 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, - 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, -}; - -static void createHuffmanHeader(unsigned char*& p, - unsigned char const* codelens, - int ncodes, - unsigned char const* symbols, - int nsymbols, - int tableNo, int tableClass) { - *p++ = 0xff; *p++ = MARKER_DHT; - *p++ = 0; /* length msb */ - *p++ = 3 + ncodes + nsymbols; /* length lsb */ - *p++ = (tableClass << 4) | tableNo; - memcpy(p, codelens, ncodes); - p += ncodes; - memcpy(p, symbols, nsymbols); - p += nsymbols; -} - -static unsigned computeJPEGHeaderSize(unsigned qtlen, unsigned dri) { - unsigned qtlen_half = qtlen/2; // in case qtlen is odd; shouldn't happen - return 495 + qtlen_half*2 + (dri > 0 ? 6 : 0); -} - -static void createJPEGHeader(unsigned char* buf, unsigned type, - unsigned w, unsigned h, - unsigned char const* qtables, unsigned qtlen, - unsigned dri) { - unsigned char *ptr = buf; - unsigned numQtables = qtlen > 64 ? 2 : 1; - - // MARKER_SOI: - *ptr++ = 0xFF; *ptr++ = MARKER_SOI; - - // MARKER_APP_FIRST: - *ptr++ = 0xFF; *ptr++ = MARKER_APP_FIRST; - *ptr++ = 0x00; *ptr++ = 0x10; // size of chunk - *ptr++ = 'J'; *ptr++ = 'F'; *ptr++ = 'I'; *ptr++ = 'F'; *ptr++ = 0x00; - *ptr++ = 0x01; *ptr++ = 0x01; // JFIF format version (1.1) - *ptr++ = 0x00; // no units - *ptr++ = 0x00; *ptr++ = 0x01; // Horizontal pixel aspect ratio - *ptr++ = 0x00; *ptr++ = 0x01; // Vertical pixel aspect ratio - *ptr++ = 0x00; *ptr++ = 0x00; // no thumbnail - - // MARKER_DRI: - if (dri > 0) { - *ptr++ = 0xFF; *ptr++ = MARKER_DRI; - *ptr++ = 0x00; *ptr++ = 0x04; // size of chunk - *ptr++ = (BYTE)(dri >> 8); *ptr++ = (BYTE)(dri); // restart interval - } - - // MARKER_DQT (luma): - unsigned tableSize = numQtables == 1 ? qtlen : qtlen/2; - *ptr++ = 0xFF; *ptr++ = MARKER_DQT; - *ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk - *ptr++ = 0x00; // precision(0), table id(0) - memcpy(ptr, qtables, tableSize); - qtables += tableSize; - ptr += tableSize; - - if (numQtables > 1) { - unsigned tableSize = qtlen - qtlen/2; - // MARKER_DQT (chroma): - *ptr++ = 0xFF; *ptr++ = MARKER_DQT; - *ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk - *ptr++ = 0x01; // precision(0), table id(1) - memcpy(ptr, qtables, tableSize); - qtables += tableSize; - ptr += tableSize; - } - - // MARKER_SOF0: - *ptr++ = 0xFF; *ptr++ = MARKER_SOF0; - *ptr++ = 0x00; *ptr++ = 0x11; // size of chunk - *ptr++ = 0x08; // sample precision - *ptr++ = (BYTE)(h >> 8); - *ptr++ = (BYTE)(h); // number of lines (must be a multiple of 8) - *ptr++ = (BYTE)(w >> 8); - *ptr++ = (BYTE)(w); // number of columns (must be a multiple of 8) - *ptr++ = 0x03; // number of components - *ptr++ = 0x01; // id of component - *ptr++ = type ? 0x22 : 0x21; // sampling ratio (h,v) - *ptr++ = 0x00; // quant table id - *ptr++ = 0x02; // id of component - *ptr++ = 0x11; // sampling ratio (h,v) - *ptr++ = numQtables == 1 ? 0x00 : 0x01; // quant table id - *ptr++ = 0x03; // id of component - *ptr++ = 0x11; // sampling ratio (h,v) - *ptr++ = 0x01; // quant table id - - createHuffmanHeader(ptr, lum_dc_codelens, sizeof lum_dc_codelens, - lum_dc_symbols, sizeof lum_dc_symbols, 0, 0); - createHuffmanHeader(ptr, lum_ac_codelens, sizeof lum_ac_codelens, - lum_ac_symbols, sizeof lum_ac_symbols, 0, 1); - createHuffmanHeader(ptr, chm_dc_codelens, sizeof chm_dc_codelens, - chm_dc_symbols, sizeof chm_dc_symbols, 1, 0); - createHuffmanHeader(ptr, chm_ac_codelens, sizeof chm_ac_codelens, - chm_ac_symbols, sizeof chm_ac_symbols, 1, 1); - - // MARKER_SOS: - *ptr++ = 0xFF; *ptr++ = MARKER_SOS; - *ptr++ = 0x00; *ptr++ = 0x0C; // size of chunk - *ptr++ = 0x03; // number of components - *ptr++ = 0x01; // id of component - *ptr++ = 0x00; // huffman table id (DC, AC) - *ptr++ = 0x02; // id of component - *ptr++ = 0x11; // huffman table id (DC, AC) - *ptr++ = 0x03; // id of component - *ptr++ = 0x11; // huffman table id (DC, AC) - *ptr++ = 0x00; // start of spectral - *ptr++ = 0x3F; // end of spectral - *ptr++ = 0x00; // successive approximation bit position (high, low) -} - -// The default 'luma' and 'chroma' quantizer tables, in zigzag order: -static unsigned char const defaultQuantizers[128] = { - // luma table: - 16, 11, 12, 14, 12, 10, 16, 14, - 13, 14, 18, 17, 16, 19, 24, 40, - 26, 24, 22, 22, 24, 49, 35, 37, - 29, 40, 58, 51, 61, 60, 57, 51, - 56, 55, 64, 72, 92, 78, 64, 68, - 87, 69, 55, 56, 80, 109, 81, 87, - 95, 98, 103, 104, 103, 62, 77, 113, - 121, 112, 100, 120, 92, 101, 103, 99, - // chroma table: - 17, 18, 18, 24, 21, 24, 47, 26, - 26, 47, 99, 66, 56, 66, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 -}; - -static void makeDefaultQtables(unsigned char* resultTables, unsigned Q) { - int factor = Q; - int q; - - if (Q < 1) factor = 1; - else if (Q > 99) factor = 99; - - if (Q < 50) { - q = 5000 / factor; - } else { - q = 200 - factor*2; - } - - for (int i = 0; i < 128; ++i) { - int newVal = (defaultQuantizers[i]*q + 50)/100; - if (newVal < 1) newVal = 1; - else if (newVal > 255) newVal = 255; - resultTables[i] = newVal; - } -} - -Boolean JPEGVideoRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - unsigned char* headerStart = packet->data(); - unsigned packetSize = packet->dataSize(); - - unsigned char* qtables = NULL; - unsigned qtlen = 0; - unsigned dri = 0; - - // There's at least 8-byte video-specific header - /* -0 1 2 3 -0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Type-specific | Fragment Offset | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Type | Q | Width | Height | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - if (packetSize < 8) return False; - - resultSpecialHeaderSize = 8; - - unsigned Offset = (unsigned)((DWORD)headerStart[1] << 16 | (DWORD)headerStart[2] << 8 | (DWORD)headerStart[3]); - unsigned Type = (unsigned)headerStart[4]; - unsigned type = Type & 1; - unsigned Q = (unsigned)headerStart[5]; - unsigned width = (unsigned)headerStart[6] * 8; - if (width == 0) width = 256*8; // special case - unsigned height = (unsigned)headerStart[7] * 8; - if (height == 0) height = 256*8; // special case - - if (Type > 63) { - // Restart Marker header present - /* -0 1 2 3 -0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Restart Interval |F|L| Restart Count | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - if (packetSize < resultSpecialHeaderSize + 4) return False; - - unsigned RestartInterval = (unsigned)((WORD)headerStart[resultSpecialHeaderSize] << 8 | (WORD)headerStart[resultSpecialHeaderSize + 1]); - dri = RestartInterval; - resultSpecialHeaderSize += 4; - } - - if (Offset == 0) { - if (Q > 127) { - // Quantization Table header present -/* -0 1 2 3 -0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| MBZ | Precision | Length | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -| Quantization Table Data | -| ... | -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ - if (packetSize < resultSpecialHeaderSize + 4) return False; - - unsigned MBZ = (unsigned)headerStart[resultSpecialHeaderSize]; - if (MBZ == 0) { - // unsigned Precision = (unsigned)headerStart[resultSpecialHeaderSize + 1]; - unsigned Length = (unsigned)((WORD)headerStart[resultSpecialHeaderSize + 2] << 8 | (WORD)headerStart[resultSpecialHeaderSize + 3]); - - //ASSERT(Length == 128); - - resultSpecialHeaderSize += 4; - - if (packetSize < resultSpecialHeaderSize + Length) return False; - - if (qtables) delete [] qtables; - - qtlen = Length; - qtables = &headerStart[resultSpecialHeaderSize]; - - resultSpecialHeaderSize += Length; - } - } - } - - // If this is the first (or only) fragment of a JPEG frame, then we need - // to synthesize a JPEG header, and prepend it to the incoming data. - // Hack: We can do this because we allowed space for it in - // our special "JPEGBufferedPacket" subclass. We also adjust - // "resultSpecialHeaderSize" to compensate for this, by subtracting - // the size of the synthesized header. Note that this will cause - // "resultSpecialHeaderSize" to become negative, but the code that called - // us (in "MultiFramedRTPSource") will handle this properly. - if (Offset == 0) { - unsigned char newQtables[128]; - if (qtlen == 0) { - // A quantization table was not present in the RTP JPEG header, - // so use the default tables, scaled according to the "Q" factor: - makeDefaultQtables(newQtables, Q); - qtables = newQtables; - qtlen = sizeof newQtables; - } - - unsigned hdrlen = computeJPEGHeaderSize(qtlen, dri); - resultSpecialHeaderSize -= hdrlen; // goes negative - headerStart += (int)resultSpecialHeaderSize; // goes backward - createJPEGHeader(headerStart, type, width, height, qtables, qtlen, dri); - } - - fCurrentPacketBeginsFrame = (Offset == 0); - - // The RTP "M" (marker) bit indicates the last fragment of a frame: - ((JPEGBufferedPacket*)packet)->completesFrame - = fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); - - return True; -} - -char const* JPEGVideoRTPSource::MIMEtype() const { - return "video/JPEG"; -} - -////////// JPEGBufferedPacket and JPEGBufferedPacketFactory implementation - -void JPEGBufferedPacket::reset() { - BufferedPacket::reset(); - - // Move our "fHead" and "fTail" forward, to allow space for a synthesized - // JPEG header to precede the RTP data that comes in over the network. - unsigned offset = MAX_JPEG_HEADER_SIZE; - if (offset > fPacketSize) offset = fPacketSize; // shouldn't happen - fHead = fTail = offset; -} - -unsigned JPEGBufferedPacket -::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { - // Normally, the enclosed frame size is just "dataSize". If, however, - // the frame does not end with the "EOI" marker, then add this now: - if (completesFrame && dataSize >= 2 && - !(framePtr[dataSize-2] == 0xFF && framePtr[dataSize-1] == MARKER_EOI)) { - framePtr[dataSize++] = 0xFF; - framePtr[dataSize++] = MARKER_EOI; - } - return dataSize; -} - -BufferedPacket* JPEGBufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* /*ourSource*/) { - return new JPEGBufferedPacket; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoSource.cpp deleted file mode 100644 index 53ac8f11c5f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/JPEGVideoSource.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// JPEG video sources -// Implementation - -#include "JPEGVideoSource.hh" - -JPEGVideoSource::JPEGVideoSource(UsageEnvironment& env) - : FramedSource(env) { -} - -JPEGVideoSource::~JPEGVideoSource() { -} - -u_int8_t const* JPEGVideoSource::quantizationTables(u_int8_t& precision, - u_int16_t& length) { - // Default implementation - precision = 0; - length = 0; - return NULL; -} - -Boolean JPEGVideoSource::isJPEGVideoSource() const { - return True; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADU.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3ADU.cpp deleted file mode 100644 index c628c79fb86..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADU.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// 'ADU' MP3 streams (for improved loss-tolerance) -// Implementation - -#include "MP3ADU.hh" -#include "MP3ADUdescriptor.hh" -#include "MP3Internals.hh" -#include - -#ifdef TEST_LOSS -#include "GroupsockHelper.hh" -#endif - -// Segment data structures, used in the implementation below: - -#define SegmentBufSize 2000 /* conservatively high */ - -class Segment { -public: - unsigned char buf[SegmentBufSize]; - unsigned char* dataStart() { return &buf[descriptorSize]; } - unsigned frameSize; // if it's a non-ADU frame - unsigned dataHere(); // if it's a non-ADU frame - - unsigned descriptorSize; - static unsigned const headerSize; - unsigned sideInfoSize, aduSize; - unsigned backpointer; - - struct timeval presentationTime; - unsigned durationInMicroseconds; -}; - -unsigned const Segment::headerSize = 4; - -#define SegmentQueueSize 10 - -class SegmentQueue { -public: - SegmentQueue(Boolean directionIsToADU, Boolean includeADUdescriptors) - : fDirectionIsToADU(directionIsToADU), - fIncludeADUdescriptors(includeADUdescriptors) { - reset(); - } - - Segment s[SegmentQueueSize]; - - unsigned headIndex() {return fHeadIndex;} - Segment& headSegment() {return s[fHeadIndex];} - - unsigned nextFreeIndex() {return fNextFreeIndex;} - Segment& nextFreeSegment() {return s[fNextFreeIndex];} - Boolean isEmpty() {return isEmptyOrFull() && totalDataSize() == 0;} - Boolean isFull() {return isEmptyOrFull() && totalDataSize() > 0;} - - static unsigned nextIndex(unsigned ix) {return (ix+1)%SegmentQueueSize;} - static unsigned prevIndex(unsigned ix) {return (ix+SegmentQueueSize-1)%SegmentQueueSize;} - - unsigned totalDataSize() {return fTotalDataSize;} - - void enqueueNewSegment(FramedSource* inputSource, FramedSource* usingSource); - - Boolean dequeue(); - - Boolean insertDummyBeforeTail(unsigned backpointer); - - void reset() { fHeadIndex = fNextFreeIndex = fTotalDataSize = 0; } - -private: - static void sqAfterGettingSegment(void* clientData, - unsigned numBytesRead, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - - Boolean sqAfterGettingCommon(Segment& seg, unsigned numBytesRead); - Boolean isEmptyOrFull() {return headIndex() == nextFreeIndex();} - - unsigned fHeadIndex, fNextFreeIndex, fTotalDataSize; - - // The following is used for asynchronous reads: - FramedSource* fUsingSource; - - // This tells us whether the direction in which we're being used - // is MP3->ADU, or vice-versa. (This flag is used for debugging output.) - Boolean fDirectionIsToADU; - - // The following is true iff we're used to enqueue incoming - // ADU frames, and these have an ADU descriptor in front - Boolean fIncludeADUdescriptors; -}; - -////////// ADUFromMP3Source ////////// - -ADUFromMP3Source::ADUFromMP3Source(UsageEnvironment& env, - FramedSource* inputSource, - Boolean includeADUdescriptors) - : FramedFilter(env, inputSource), - fAreEnqueueingMP3Frame(False), - fSegments(new SegmentQueue(True /* because we're MP3->ADU */, - False /*no descriptors in incoming frames*/)), - fIncludeADUdescriptors(includeADUdescriptors), - fTotalDataSizeBeforePreviousRead(0), fScale(1), fFrameCounter(0) { -} - -ADUFromMP3Source::~ADUFromMP3Source() { - delete fSegments; -} - - -char const* ADUFromMP3Source::MIMEtype() const { - return "audio/MPA-ROBUST"; -} - -ADUFromMP3Source* ADUFromMP3Source::createNew(UsageEnvironment& env, - FramedSource* inputSource, - Boolean includeADUdescriptors) { - // The source must be a MPEG audio source: - if (strcmp(inputSource->MIMEtype(), "audio/MPEG") != 0) { - env.setResultMsg(inputSource->name(), " is not an MPEG audio source"); - return NULL; - } - - return new ADUFromMP3Source(env, inputSource, includeADUdescriptors); -} - -void ADUFromMP3Source::resetInput() { - fSegments->reset(); -} - -Boolean ADUFromMP3Source::setScaleFactor(int scale) { - if (scale < 1) return False; - fScale = scale; - return True; -} - -void ADUFromMP3Source::doGetNextFrame() { - if (!fAreEnqueueingMP3Frame) { - // Arrange to enqueue a new MP3 frame: - fTotalDataSizeBeforePreviousRead = fSegments->totalDataSize(); - fAreEnqueueingMP3Frame = True; - fSegments->enqueueNewSegment(fInputSource, this); - } else { - // Deliver an ADU from a previously-read MP3 frame: - fAreEnqueueingMP3Frame = False; - - if (!doGetNextFrame1()) { - // An internal error occurred; act as if our source went away: - FramedSource::handleClosure(this); - } - } -} - -Boolean ADUFromMP3Source::doGetNextFrame1() { - // First, check whether we have enough previously-read data to output an - // ADU for the last-read MP3 frame: - unsigned tailIndex; - Segment* tailSeg; - Boolean needMoreData; - - if (fSegments->isEmpty()) { - needMoreData = True; - tailSeg = NULL; tailIndex = 0; // unneeded, but stops compiler warnings - } else { - tailIndex = SegmentQueue::prevIndex(fSegments->nextFreeIndex()); - tailSeg = &(fSegments->s[tailIndex]); - - needMoreData - = fTotalDataSizeBeforePreviousRead < tailSeg->backpointer // bp points back too far - || tailSeg->backpointer + tailSeg->dataHere() < tailSeg->aduSize; // not enough data - } - - if (needMoreData) { - // We don't have enough data to output an ADU from the last-read MP3 - // frame, so need to read another one and try again: - doGetNextFrame(); - return True; - } - - // Output an ADU from the tail segment: - fFrameSize = tailSeg->headerSize+tailSeg->sideInfoSize+tailSeg->aduSize; - fPresentationTime = tailSeg->presentationTime; - fDurationInMicroseconds = tailSeg->durationInMicroseconds; - unsigned descriptorSize - = fIncludeADUdescriptors ? ADUdescriptor::computeSize(fFrameSize) : 0; -#ifdef DEBUG - fprintf(stderr, "m->a:outputting ADU %d<-%d, nbr:%d, sis:%d, dh:%d, (descriptor size: %d)\n", tailSeg->aduSize, tailSeg->backpointer, fFrameSize, tailSeg->sideInfoSize, tailSeg->dataHere(), descriptorSize); -#endif - if (descriptorSize + fFrameSize > fMaxSize) { - envir() << "ADUFromMP3Source::doGetNextFrame1(): not enough room (" - << descriptorSize + fFrameSize << ">" - << fMaxSize << ")\n"; - fFrameSize = 0; - return False; - } - - unsigned char* toPtr = fTo; - // output the ADU descriptor: - if (fIncludeADUdescriptors) { - fFrameSize += ADUdescriptor::generateDescriptor(toPtr, fFrameSize); - } - - // output header and side info: - memmove(toPtr, tailSeg->dataStart(), - tailSeg->headerSize + tailSeg->sideInfoSize); - toPtr += tailSeg->headerSize + tailSeg->sideInfoSize; - - // go back to the frame that contains the start of our data: - unsigned offset = 0; - unsigned i = tailIndex; - unsigned prevBytes = tailSeg->backpointer; - while (prevBytes > 0) { - i = SegmentQueue::prevIndex(i); - unsigned dataHere = fSegments->s[i].dataHere(); - if (dataHere < prevBytes) { - prevBytes -= dataHere; - } else { - offset = dataHere - prevBytes; - break; - } - } - - // dequeue any segments that we no longer need: - while (fSegments->headIndex() != i) { - fSegments->dequeue(); // we're done with it - } - - unsigned bytesToUse = tailSeg->aduSize; - while (bytesToUse > 0) { - Segment& seg = fSegments->s[i]; - unsigned char* fromPtr - = &seg.dataStart()[seg.headerSize + seg.sideInfoSize + offset]; - unsigned dataHere = seg.dataHere() - offset; - unsigned bytesUsedHere = dataHere < bytesToUse ? dataHere : bytesToUse; - memmove(toPtr, fromPtr, bytesUsedHere); - bytesToUse -= bytesUsedHere; - toPtr += bytesUsedHere; - offset = 0; - i = SegmentQueue::nextIndex(i); - } - - - if (fFrameCounter++%fScale == 0) { - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); - } else { - // Don't use this frame; get another one: - doGetNextFrame(); - } - - return True; -} - - -////////// MP3FromADUSource ////////// - -MP3FromADUSource::MP3FromADUSource(UsageEnvironment& env, - FramedSource* inputSource, - Boolean includeADUdescriptors) - : FramedFilter(env, inputSource), - fAreEnqueueingADU(False), - fSegments(new SegmentQueue(False /* because we're ADU->MP3 */, - includeADUdescriptors)), - fIncludeADUdescriptors(includeADUdescriptors) { -} - -MP3FromADUSource::~MP3FromADUSource() { - delete fSegments; -} - -char const* MP3FromADUSource::MIMEtype() const { - return "audio/MPEG"; -} - -MP3FromADUSource* MP3FromADUSource::createNew(UsageEnvironment& env, - FramedSource* inputSource, - Boolean includeADUdescriptors) { - // The source must be an MP3 ADU source: - if (strcmp(inputSource->MIMEtype(), "audio/MPA-ROBUST") != 0) { - env.setResultMsg(inputSource->name(), " is not an MP3 ADU source"); - return NULL; - } - - return new MP3FromADUSource(env, inputSource, includeADUdescriptors); -} - - -void MP3FromADUSource::doGetNextFrame() { - if (fAreEnqueueingADU) insertDummyADUsIfNecessary(); - fAreEnqueueingADU = False; - - if (needToGetAnADU()) { - // Before returning a frame, we must enqueue at least one ADU: -#ifdef TEST_LOSS - NOTE: This code no longer works, because it uses synchronous reads, - which are no longer supported. - static unsigned const framesPerPacket = 10; - static unsigned const frameCount = 0; - static Boolean packetIsLost; - while (1) { - if ((frameCount++)%framesPerPacket == 0) { - packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss ##### - } - - if (packetIsLost) { - // Read and discard the next input frame (that would be part of - // a lost packet): - Segment dummySegment; - unsigned numBytesRead; - struct timeval presentationTime; - // (this works only if the source can be read synchronously) - fInputSource->syncGetNextFrame(dummySegment.buf, - sizeof dummySegment.buf, numBytesRead, - presentationTime); - } else { - break; // from while (1) - } - } -#endif - - fAreEnqueueingADU = True; - fSegments->enqueueNewSegment(fInputSource, this); - } else { - // Return a frame now: - generateFrameFromHeadADU(); - // sets fFrameSize, fPresentationTime, and fDurationInMicroseconds - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); - } -} - -Boolean MP3FromADUSource::needToGetAnADU() { - // Check whether we need to first enqueue a new ADU before we - // can generate a frame for our head ADU. - Boolean needToEnqueue = True; - - if (!fSegments->isEmpty()) { - unsigned index = fSegments->headIndex(); - Segment* seg = &(fSegments->headSegment()); - int const endOfHeadFrame = (int) seg->dataHere(); - unsigned frameOffset = 0; - - while (1) { - int endOfData = frameOffset - seg->backpointer + seg->aduSize; - if (endOfData >= endOfHeadFrame) { - // We already have enough data to generate a frame - needToEnqueue = False; - break; - } - - frameOffset += seg->dataHere(); - index = SegmentQueue::nextIndex(index); - if (index == fSegments->nextFreeIndex()) break; - seg = &(fSegments->s[index]); - } - } - - return needToEnqueue; -} - -void MP3FromADUSource::insertDummyADUsIfNecessary() { - if (fSegments->isEmpty()) return; // shouldn't happen - - // The tail segment (ADU) is assumed to have been recently - // enqueued. If its backpointer would overlap the data - // of the previous ADU, then we need to insert one or more - // empty, 'dummy' ADUs ahead of it. (This situation should occur - // only if an intermediate ADU was lost.) - - unsigned tailIndex - = SegmentQueue::prevIndex(fSegments->nextFreeIndex()); - Segment* tailSeg = &(fSegments->s[tailIndex]); - - while (1) { - unsigned prevADUend; // relative to the start of the new ADU - if (fSegments->headIndex() != tailIndex) { - // there is a previous segment - unsigned prevIndex = SegmentQueue::prevIndex(tailIndex); - Segment& prevSegment = fSegments->s[prevIndex]; - prevADUend = prevSegment.dataHere() + prevSegment.backpointer; - if (prevSegment.aduSize > prevADUend) { - // shouldn't happen if the previous ADU was well-formed - prevADUend = 0; - } else { - prevADUend -= prevSegment.aduSize; - } - } else { - prevADUend = 0; - } - - if (tailSeg->backpointer > prevADUend) { - // We need to insert a dummy ADU in front of the tail -#ifdef DEBUG - fprintf(stderr, "a->m:need to insert a dummy ADU (%d, %d, %d) [%d, %d]\n", tailSeg->backpointer, prevADUend, tailSeg->dataHere(), fSegments->headIndex(), fSegments->nextFreeIndex()); -#endif - tailIndex = fSegments->nextFreeIndex(); - if (!fSegments->insertDummyBeforeTail(prevADUend)) return; - tailSeg = &(fSegments->s[tailIndex]); - } else { - break; // no more dummy ADUs need to be inserted - } - } -} - -Boolean MP3FromADUSource::generateFrameFromHeadADU() { - // Output a frame for the head ADU: - if (fSegments->isEmpty()) return False; - unsigned index = fSegments->headIndex(); - Segment* seg = &(fSegments->headSegment()); -#ifdef DEBUG - fprintf(stderr, "a->m:outputting frame for %d<-%d (fs %d, dh %d), (descriptorSize: %d)\n", seg->aduSize, seg->backpointer, seg->frameSize, seg->dataHere(), seg->descriptorSize); -#endif - unsigned char* toPtr = fTo; - - // output header and side info: - fFrameSize = seg->frameSize; - fPresentationTime = seg->presentationTime; - fDurationInMicroseconds = seg->durationInMicroseconds; - memmove(toPtr, seg->dataStart(), seg->headerSize + seg->sideInfoSize); - toPtr += seg->headerSize + seg->sideInfoSize; - - // zero out the rest of the frame, in case ADU data doesn't fill it all in - unsigned bytesToZero = seg->dataHere(); - for (unsigned i = 0; i < bytesToZero; ++i) { - toPtr[i] = '\0'; - } - - // Fill in the frame with appropriate ADU data from this and - // subsequent ADUs: - unsigned frameOffset = 0; - unsigned toOffset = 0; - unsigned const endOfHeadFrame = seg->dataHere(); - - while (toOffset < endOfHeadFrame) { - int startOfData = frameOffset - seg->backpointer; - if (startOfData > (int)endOfHeadFrame) break; // no more ADUs needed - - int endOfData = startOfData + seg->aduSize; - if (endOfData > (int)endOfHeadFrame) { - endOfData = endOfHeadFrame; - } - - unsigned fromOffset; - if (startOfData <= (int)toOffset) { - fromOffset = toOffset - startOfData; - startOfData = toOffset; - if (endOfData < startOfData) endOfData = startOfData; - } else { - fromOffset = 0; - - // we may need some padding bytes beforehand - unsigned bytesToZero = startOfData - toOffset; -#ifdef DEBUG - if (bytesToZero > 0) fprintf(stderr, "a->m:outputting %d zero bytes (%d, %d, %d, %d)\n", bytesToZero, startOfData, toOffset, frameOffset, seg->backpointer); -#endif - toOffset += bytesToZero; - } - - unsigned char* fromPtr - = &seg->dataStart()[seg->headerSize + seg->sideInfoSize + fromOffset]; - unsigned bytesUsedHere = endOfData - startOfData; -#ifdef DEBUG - if (bytesUsedHere > 0) fprintf(stderr, "a->m:outputting %d bytes from %d<-%d\n", bytesUsedHere, seg->aduSize, seg->backpointer); -#endif - memmove(toPtr + toOffset, fromPtr, bytesUsedHere); - toOffset += bytesUsedHere; - - frameOffset += seg->dataHere(); - index = SegmentQueue::nextIndex(index); - if (index == fSegments->nextFreeIndex()) break; - seg = &(fSegments->s[index]); - } - - fSegments->dequeue(); - - return True; -} - - -////////// Segment ////////// - -unsigned Segment::dataHere() { - int result = frameSize - (headerSize + sideInfoSize); - if (result < 0) { - return 0; - } - - return (unsigned)result; -} - -////////// SegmentQueue ////////// - -void SegmentQueue::enqueueNewSegment(FramedSource* inputSource, - FramedSource* usingSource) { - if (isFull()) { - usingSource->envir() << "SegmentQueue::enqueueNewSegment() overflow\n"; - FramedSource::handleClosure(usingSource); - return; - } - - fUsingSource = usingSource; - - Segment& seg = nextFreeSegment(); - inputSource->getNextFrame(seg.buf, sizeof seg.buf, - sqAfterGettingSegment, this, - FramedSource::handleClosure, usingSource); -} - -void SegmentQueue::sqAfterGettingSegment(void* clientData, - unsigned numBytesRead, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - SegmentQueue* segQueue = (SegmentQueue*)clientData; - Segment& seg = segQueue->nextFreeSegment(); - - seg.presentationTime = presentationTime; - seg.durationInMicroseconds = durationInMicroseconds; - - if (segQueue->sqAfterGettingCommon(seg, numBytesRead)) { -#ifdef DEBUG - char const* direction = segQueue->fDirectionIsToADU ? "m->a" : "a->m"; - fprintf(stderr, "%s:read frame %d<-%d, fs:%d, sis:%d, dh:%d, (descriptor size: %d)\n", direction, seg.aduSize, seg.backpointer, seg.frameSize, seg.sideInfoSize, seg.dataHere(), seg.descriptorSize); -#endif - } - - // Continue our original calling source where it left off: - segQueue->fUsingSource->doGetNextFrame(); -} - -// Common code called after a new segment is enqueued -Boolean SegmentQueue::sqAfterGettingCommon(Segment& seg, - unsigned numBytesRead) { - unsigned char* fromPtr = seg.buf; - - if (fIncludeADUdescriptors) { - // The newly-read data is assumed to be an ADU with a descriptor - // in front - (void)ADUdescriptor::getRemainingFrameSize(fromPtr); - seg.descriptorSize = (unsigned)(fromPtr-seg.buf); - } else { - seg.descriptorSize = 0; - } - - // parse the MP3-specific info in the frame to get the ADU params - unsigned hdr; - MP3SideInfo sideInfo; - if (!GetADUInfoFromMP3Frame(fromPtr, numBytesRead, - hdr, seg.frameSize, - sideInfo, seg.sideInfoSize, - seg.backpointer, seg.aduSize)) { - return False; - } - - // If we've just read an ADU (rather than a regular MP3 frame), then use the - // entire "numBytesRead" data for the 'aduSize', so that we include any - // 'ancillary data' that may be present at the end of the ADU: - if (!fDirectionIsToADU) { - unsigned newADUSize - = numBytesRead - seg.descriptorSize - 4/*header size*/ - seg.sideInfoSize; - if (newADUSize > seg.aduSize) seg.aduSize = newADUSize; - } - fTotalDataSize += seg.dataHere(); - fNextFreeIndex = nextIndex(fNextFreeIndex); - - return True; -} - -Boolean SegmentQueue::dequeue() { - if (isEmpty()) { - fUsingSource->envir() << "SegmentQueue::dequeue(): underflow!\n"; - return False; - } - - Segment& seg = s[headIndex()]; - fTotalDataSize -= seg.dataHere(); - fHeadIndex = nextIndex(fHeadIndex); - return True; -} - -Boolean SegmentQueue::insertDummyBeforeTail(unsigned backpointer) { - if (isEmptyOrFull()) return False; - - // Copy the current tail segment to its new position, then modify the - // old tail segment to be a 'dummy' ADU - - unsigned newTailIndex = nextFreeIndex(); - Segment& newTailSeg = s[newTailIndex]; - - unsigned oldTailIndex = prevIndex(newTailIndex); - Segment& oldTailSeg = s[oldTailIndex]; - - newTailSeg = oldTailSeg; // structure copy - - // Begin by setting (replacing) the ADU descriptor of the dummy ADU: - unsigned char* ptr = oldTailSeg.buf; - if (fIncludeADUdescriptors) { - unsigned remainingFrameSize - = oldTailSeg.headerSize + oldTailSeg.sideInfoSize + 0 /* 0-size ADU */; - unsigned currentDescriptorSize = oldTailSeg.descriptorSize; - - if (currentDescriptorSize == 2) { - ADUdescriptor::generateTwoByteDescriptor(ptr, remainingFrameSize); - } else { - (void)ADUdescriptor::generateDescriptor(ptr, remainingFrameSize); - } - } - - // Then zero out the side info of the dummy frame: - if (!ZeroOutMP3SideInfo(ptr, oldTailSeg.frameSize, - backpointer)) return False; - - unsigned dummyNumBytesRead - = oldTailSeg.descriptorSize + 4/*header size*/ + oldTailSeg.sideInfoSize; - return sqAfterGettingCommon(oldTailSeg, dummyNumBytesRead); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADURTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3ADURTPSink.cpp deleted file mode 100644 index 61e58c8f61d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADURTPSink.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for 'ADUized' MP3 frames ("mpa-robust") -// Implementation - -#include "MP3ADURTPSink.hh" - -MP3ADURTPSink::MP3ADURTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char RTPPayloadType) - : AudioRTPSink(env, RTPgs, RTPPayloadType, 90000, "MPA-ROBUST") { -} - -MP3ADURTPSink::~MP3ADURTPSink() { -} - -MP3ADURTPSink* -MP3ADURTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char RTPPayloadType) { - return new MP3ADURTPSink(env, RTPgs, RTPPayloadType); -} - -static void badDataSize(UsageEnvironment& env, unsigned numBytesInFrame) { - env << "MP3ADURTPSink::doSpecialFrameHandling(): invalid size (" - << numBytesInFrame << ") of non-fragmented input ADU!\n"; -} - -void MP3ADURTPSink::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - // If this is the first (or only) fragment of an ADU, then - // check the "ADU descriptor" (that should be at the front) for validity: - if (fragmentationOffset == 0) { - unsigned aduDescriptorSize; - - if (numBytesInFrame < 1) { - badDataSize(envir(), numBytesInFrame); - return; - } - if (frameStart[0]&0x40) { - // We have a 2-byte ADU descriptor - aduDescriptorSize = 2; - if (numBytesInFrame < 2) { - badDataSize(envir(), numBytesInFrame); - return; - } - fCurADUSize = ((frameStart[0]&~0xC0)<<8) | frameStart[1]; - } else { - // We have a 1-byte ADU descriptor - aduDescriptorSize = 1; - fCurADUSize = frameStart[0]&~0x80; - } - - if (frameStart[0]&0x80) { - envir() << "Unexpected \"C\" bit seen on non-fragment input ADU!\n"; - return; - } - - // Now, check whether the ADU size in the ADU descriptor is consistent - // with the total data size of (all fragments of) the input frame: - unsigned expectedADUSize = - fragmentationOffset + numBytesInFrame + numRemainingBytes - - aduDescriptorSize; - if (fCurADUSize != expectedADUSize) { - envir() << "MP3ADURTPSink::doSpecialFrameHandling(): Warning: Input ADU size " - << expectedADUSize << " (=" << fragmentationOffset - << "+" << numBytesInFrame << "+" << numRemainingBytes - << "-" << aduDescriptorSize - << ") did not match the value (" << fCurADUSize - << ") in the ADU descriptor!\n"; - fCurADUSize = expectedADUSize; - } - } else { - // This is the second (or subsequent) fragment. - // Insert a new ADU descriptor: - unsigned char aduDescriptor[2]; - aduDescriptor[0] = 0xC0|(fCurADUSize>>8); - aduDescriptor[1] = fCurADUSize&0xFF; - setSpecialHeaderBytes(aduDescriptor, 2); - } - - // Important: Also call our base class's doSpecialFrameHandling(), - // to set the packet's timestamp: - MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, - frameStart, numBytesInFrame, - frameTimestamp, - numRemainingBytes); -} - -unsigned MP3ADURTPSink::specialHeaderSize() const { - // Normally there's no special header. - // (The "ADU descriptor" is already present in the data.) - unsigned specialHeaderSize = 0; - - // However, if we're about to output the second (or subsequent) fragment - // of a fragmented ADU, then we need to insert a new ADU descriptor at - // the front of the packet: - if (curFragmentationOffset() > 0) { - specialHeaderSize = 2; - } - - return specialHeaderSize; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADURTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3ADURTPSource.cpp deleted file mode 100644 index 83fe7f718e7..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADURTPSource.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP source for 'ADUized' MP3 frames ("mpa-robust") -// Implementation - -#include "MP3ADURTPSource.hh" -#include "MP3ADUdescriptor.hh" - -////////// ADUBufferedPacket and ADUBufferedPacketFactory ////////// - -class ADUBufferedPacket: public BufferedPacket { -private: // redefined virtual functions - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); -}; - -class ADUBufferedPacketFactory: public BufferedPacketFactory { -private: // redefined virtual functions - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - -///////// MP3ADURTPSource implementation //////// - -MP3ADURTPSource* -MP3ADURTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new MP3ADURTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -MP3ADURTPSource::MP3ADURTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency, - new ADUBufferedPacketFactory) { -} - -MP3ADURTPSource::~MP3ADURTPSource() { -} - -char const* MP3ADURTPSource::MIMEtype() const { - return "audio/MPA-ROBUST"; -} - -////////// ADUBufferedPacket and ADUBufferredPacketFactory implementation - -unsigned ADUBufferedPacket -::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { - // Return the size of the next MP3 'ADU', on the assumption that - // the input data is ADU-encoded MP3 frames. - unsigned char* frameDataPtr = framePtr; - unsigned remainingFrameSize - = ADUdescriptor::getRemainingFrameSize(frameDataPtr); - unsigned descriptorSize = (unsigned)(frameDataPtr - framePtr); - unsigned fullADUSize = descriptorSize + remainingFrameSize; - - return (fullADUSize <= dataSize) ? fullADUSize : dataSize; -} - -BufferedPacket* ADUBufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* /*ourSource*/) { - return new ADUBufferedPacket; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUTranscoder.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUTranscoder.cpp deleted file mode 100644 index 32b77246c7b..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUTranscoder.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Transcoder for ADUized MP3 frames -// Implementation - -#include "MP3ADUTranscoder.hh" -#include "MP3Internals.hh" -#include - -MP3ADUTranscoder::MP3ADUTranscoder(UsageEnvironment& env, - unsigned outBitrate /* in kbps */, - FramedSource* inputSource) - : FramedFilter(env, inputSource), - fOutBitrate(outBitrate), - fAvailableBytesForBackpointer(0), - fOrigADU(new unsigned char[MAX_MP3_FRAME_SIZE]) { -} - -MP3ADUTranscoder::~MP3ADUTranscoder() { - delete[] fOrigADU; -} - -MP3ADUTranscoder* MP3ADUTranscoder::createNew(UsageEnvironment& env, - unsigned outBitrate /* in kbps */, - FramedSource* inputSource) { - // The source must be an MP3 ADU source: - if (strcmp(inputSource->MIMEtype(), "audio/MPA-ROBUST") != 0) { - env.setResultMsg(inputSource->name(), " is not an MP3 ADU source"); - return NULL; - } - - return new MP3ADUTranscoder(env, outBitrate, inputSource); -} - -void MP3ADUTranscoder::getAttributes() const { - // Begin by getting the attributes from our input source: - fInputSource->getAttributes(); - - // Then modify them by appending the corrected bandwidth - char buffer[30]; - sprintf(buffer, " bandwidth %d", outBitrate()); - envir().appendToResultMsg(buffer); -} - -void MP3ADUTranscoder::doGetNextFrame() { - fInputSource->getNextFrame(fOrigADU, MAX_MP3_FRAME_SIZE, - afterGettingFrame, this, handleClosure, this); -} - -void MP3ADUTranscoder::afterGettingFrame(void* clientData, - unsigned numBytesRead, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - MP3ADUTranscoder* transcoder = (MP3ADUTranscoder*)clientData; - transcoder->afterGettingFrame1(numBytesRead, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -void MP3ADUTranscoder::afterGettingFrame1(unsigned numBytesRead, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - fNumTruncatedBytes = numTruncatedBytes; // but can we handle this being >0? ##### - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - fFrameSize = TranscodeMP3ADU(fOrigADU, numBytesRead, fOutBitrate, - fTo, fMaxSize, fAvailableBytesForBackpointer); - if (fFrameSize == 0) { // internal error - bad ADU data? - handleClosure(this); - return; - } - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUdescriptor.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUdescriptor.cpp deleted file mode 100644 index 5a1d8123faa..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUdescriptor.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Descriptor preceding frames of 'ADU' MP3 streams (for improved loss-tolerance) -// Implementation - -#include "MP3ADUdescriptor.hh" - -////////// ADUdescriptor ////////// - -//##### NOTE: For now, ignore fragmentation. Fix this later! ##### - -#define TWO_BYTE_DESCR_FLAG 0x40 - -unsigned ADUdescriptor::generateDescriptor(unsigned char*& toPtr, - unsigned remainingFrameSize) { - unsigned descriptorSize = ADUdescriptor::computeSize(remainingFrameSize); - switch (descriptorSize) { - case 1: { - *toPtr++ = (unsigned char)remainingFrameSize; - break; - } - case 2: { - generateTwoByteDescriptor(toPtr, remainingFrameSize); - break; - } - } - - return descriptorSize; -} - -void ADUdescriptor::generateTwoByteDescriptor(unsigned char*& toPtr, - unsigned remainingFrameSize) { - *toPtr++ = (TWO_BYTE_DESCR_FLAG|(unsigned char)(remainingFrameSize>>8)); - *toPtr++ = (unsigned char)(remainingFrameSize&0xFF); -} - -unsigned ADUdescriptor::getRemainingFrameSize(unsigned char*& fromPtr) { - unsigned char firstByte = *fromPtr++; - - if (firstByte&TWO_BYTE_DESCR_FLAG) { - // This is a 2-byte descriptor - unsigned char secondByte = *fromPtr++; - - return ((firstByte&0x3F)<<8) | secondByte; - } else { - // This is a 1-byte descriptor - return (firstByte&0x3F); - } -} - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUdescriptor.hh b/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUdescriptor.hh deleted file mode 100644 index 608ba5055f0..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUdescriptor.hh +++ /dev/null @@ -1,43 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Descriptor preceding frames of 'ADU' MP3 streams (for improved loss-tolerance) -// C++ header - -#ifndef _MP3_ADU_DESCRIPTOR_HH -#define _MP3_ADU_DESCRIPTOR_HH - -// A class for handling the descriptor that begins each ADU frame: -// (Note: We don't yet implement fragmentation) -class ADUdescriptor { -public: - // Operations for generating a new descriptor - static unsigned computeSize(unsigned remainingFrameSize) { - return remainingFrameSize >= 64 ? 2 : 1; - } - static unsigned generateDescriptor(unsigned char*& toPtr, unsigned remainingFrameSize); - // returns descriptor size; increments "toPtr" afterwards - static void generateTwoByteDescriptor(unsigned char*& toPtr, unsigned remainingFrameSize); - // always generates a 2-byte descriptor, even if "remainingFrameSize" is - // small enough for a 1-byte descriptor - - // Operations for reading a descriptor - static unsigned getRemainingFrameSize(unsigned char*& fromPtr); - // increments "fromPtr" afterwards -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUinterleaving.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUinterleaving.cpp deleted file mode 100644 index 594c2cc34bc..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3ADUinterleaving.cpp +++ /dev/null @@ -1,517 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Interleaving of MP3 ADUs -// Implementation - -#include "MP3ADUinterleaving.hh" -#include "MP3ADUdescriptor.hh" - -#include - -#ifdef TEST_LOSS -#include "GroupsockHelper.hh" -#endif - -////////// Interleaving ////////// - -Interleaving::Interleaving(unsigned cycleSize, - unsigned char const* cycleArray) - : fCycleSize(cycleSize) { - for (unsigned i = 0; i < fCycleSize; ++i) { - fInverseCycle[cycleArray[i]] = i; - } -} - -Interleaving::~Interleaving() { -} - -////////// MP3ADUinterleaverBase ////////// - -MP3ADUinterleaverBase::MP3ADUinterleaverBase(UsageEnvironment& env, - FramedSource* inputSource) - : FramedFilter(env, inputSource) { -} -MP3ADUinterleaverBase::~MP3ADUinterleaverBase() { -} - -FramedSource* MP3ADUinterleaverBase::getInputSource(UsageEnvironment& env, - char const* inputSourceName) { - FramedSource* inputSource; - if (!FramedSource::lookupByName(env, inputSourceName, inputSource)) - return NULL; - - if (strcmp(inputSource->MIMEtype(), "audio/MPA-ROBUST") != 0) { - env.setResultMsg(inputSourceName, " is not an MP3 ADU source"); - return NULL; - } - - return inputSource; -} - -void MP3ADUinterleaverBase::afterGettingFrame(void* clientData, - unsigned numBytesRead, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - MP3ADUinterleaverBase* interleaverBase = (MP3ADUinterleaverBase*)clientData; - // Finish up after reading: - interleaverBase->afterGettingFrame(numBytesRead, - presentationTime, durationInMicroseconds); - - // Then, continue to deliver an outgoing frame: - interleaverBase->doGetNextFrame(); -} - - -////////// InterleavingFrames (definition) ////////// - -class InterleavingFrames { -public: - InterleavingFrames(unsigned maxCycleSize); - virtual ~InterleavingFrames(); - - Boolean haveReleaseableFrame(); - void getIncomingFrameParams(unsigned char index, - unsigned char*& dataPtr, - unsigned& bytesAvailable); - void getReleasingFrameParams(unsigned char index, - unsigned char*& dataPtr, - unsigned& bytesInUse, - struct timeval& presentationTime, - unsigned& durationInMicroseconds); - void setFrameParams(unsigned char index, - unsigned char icc, unsigned char ii, - unsigned frameSize, struct timeval presentationTime, - unsigned durationInMicroseconds); - unsigned nextIndexToRelease() {return fNextIndexToRelease;} - void releaseNext(); - -private: - unsigned fMaxCycleSize; - unsigned fNextIndexToRelease; - class InterleavingFrameDescriptor* fDescriptors; -}; - -////////// MP3ADUinterleaver ////////// - - -MP3ADUinterleaver::MP3ADUinterleaver(UsageEnvironment& env, - Interleaving const& interleaving, - FramedSource* inputSource) - : MP3ADUinterleaverBase(env, inputSource), - fInterleaving(interleaving), - fFrames(new InterleavingFrames(interleaving.cycleSize())), - fII(0), fICC(0) { -} - -MP3ADUinterleaver::~MP3ADUinterleaver() { - delete fFrames; -} - -MP3ADUinterleaver* MP3ADUinterleaver::createNew(UsageEnvironment& env, - Interleaving const& interleaving, - FramedSource* inputSource) { - return new MP3ADUinterleaver(env, interleaving, inputSource); -} - -void MP3ADUinterleaver::doGetNextFrame() { - // If there's a frame immediately available, deliver it, otherwise get new - // frames from the source until one's available: - if (fFrames->haveReleaseableFrame()) { - releaseOutgoingFrame(); - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); - } else { - fPositionOfNextIncomingFrame = fInterleaving.lookupInverseCycle(fII); - unsigned char* dataPtr; - unsigned bytesAvailable; - fFrames->getIncomingFrameParams(fPositionOfNextIncomingFrame, - dataPtr, bytesAvailable); - - // Read the next incoming frame (asynchronously) - fInputSource->getNextFrame(dataPtr, bytesAvailable, - &MP3ADUinterleaverBase::afterGettingFrame, this, - handleClosure, this); - } -} - -void MP3ADUinterleaver::releaseOutgoingFrame() { - unsigned char* fromPtr; - fFrames->getReleasingFrameParams(fFrames->nextIndexToRelease(), - fromPtr, fFrameSize, - fPresentationTime, fDurationInMicroseconds); - - if (fFrameSize > fMaxSize) { - fNumTruncatedBytes = fFrameSize - fMaxSize; - fFrameSize = fMaxSize; - } - memmove(fTo, fromPtr, fFrameSize); - - fFrames->releaseNext(); -} - -void MP3ADUinterleaver::afterGettingFrame(unsigned numBytesRead, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Set the (icc,ii) and frame size of the newly-read frame: - fFrames->setFrameParams(fPositionOfNextIncomingFrame, - fICC, fII, numBytesRead, - presentationTime, durationInMicroseconds); - - // Prepare our counters for the next frame: - if (++fII == fInterleaving.cycleSize()) { - fII = 0; - fICC = (fICC+1)%8; - } -} - -////////// DeinterleavingFrames (definition) ////////// - -class DeinterleavingFrames { -public: - DeinterleavingFrames(); - virtual ~DeinterleavingFrames(); - - Boolean haveReleaseableFrame(); - void getIncomingFrameParams(unsigned char*& dataPtr, - unsigned& bytesAvailable); - void getIncomingFrameParamsAfter(unsigned frameSize, - struct timeval presentationTime, - unsigned durationInMicroseconds, - unsigned char& icc, unsigned char& ii); - void getReleasingFrameParams(unsigned char*& dataPtr, - unsigned& bytesInUse, - struct timeval& presentationTime, - unsigned& durationInMicroseconds); - void moveIncomingFrameIntoPlace(); - void releaseNext(); - void startNewCycle(); - -private: - unsigned fNextIndexToRelease; - Boolean fHaveEndedCycle; - unsigned fIIlastSeen; - unsigned fMinIndexSeen, fMaxIndexSeen; // actually, max+1 - class DeinterleavingFrameDescriptor* fDescriptors; -}; - -////////// MP3ADUdeinterleaver ////////// - -MP3ADUdeinterleaver::MP3ADUdeinterleaver(UsageEnvironment& env, - FramedSource* inputSource) - : MP3ADUinterleaverBase(env, inputSource), - fFrames(new DeinterleavingFrames), - fIIlastSeen(~0), fICClastSeen(~0) { -} - -MP3ADUdeinterleaver::~MP3ADUdeinterleaver() { - delete fFrames; -} - -MP3ADUdeinterleaver* MP3ADUdeinterleaver::createNew(UsageEnvironment& env, - FramedSource* inputSource) { - return new MP3ADUdeinterleaver(env, inputSource); -} - -void MP3ADUdeinterleaver::doGetNextFrame() { - // If there's a frame immediately available, deliver it, otherwise get new - // frames from the source until one's available: - if (fFrames->haveReleaseableFrame()) { - releaseOutgoingFrame(); - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); - } else { -#ifdef TEST_LOSS - NOTE: This code no longer works, because it uses synchronous reads, - which are no longer supported. - static unsigned const framesPerPacket = 3; - static unsigned const frameCount = 0; - static Boolean packetIsLost; - while (1) { - unsigned packetCount = frameCount/framesPerPacket; - if ((frameCount++)%framesPerPacket == 0) { - packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss ##### - } - - if (packetIsLost) { - // Read and discard the next input frame (that would be part of - // a lost packet): - unsigned char dummyBuf[2000]; - unsigned numBytesRead; - struct timeval presentationTime; - // (this works only if the source can be read synchronously) - fInputSource->syncGetNextFrame(dummyBuf, sizeof dummyBuf, - numBytesRead, presentationTime); - } else { - break; // from while (1) - } - } -#endif - unsigned char* dataPtr; - unsigned bytesAvailable; - fFrames->getIncomingFrameParams(dataPtr, bytesAvailable); - - // Read the next incoming frame (asynchronously) - fInputSource->getNextFrame(dataPtr, bytesAvailable, - &MP3ADUinterleaverBase::afterGettingFrame, this, - handleClosure, this); - } -} - -void MP3ADUdeinterleaver::afterGettingFrame(unsigned numBytesRead, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Get the (icc,ii) and set the frame size of the newly-read frame: - unsigned char icc, ii; - fFrames->getIncomingFrameParamsAfter(numBytesRead, - presentationTime, durationInMicroseconds, - icc, ii); - - // Compare these to the values we saw last: - if (icc != fICClastSeen || ii == fIIlastSeen) { - // We've started a new interleave cycle - // (or interleaving was not used). Release all - // pending ADU frames to the ADU->MP3 conversion step: - fFrames->startNewCycle(); - } else { - // We're still in the same cycle as before. - // Move the newly-read frame into place, so it can be used: - fFrames->moveIncomingFrameIntoPlace(); - } - - fICClastSeen = icc; - fIIlastSeen = ii; -} - -void MP3ADUdeinterleaver::releaseOutgoingFrame() { - unsigned char* fromPtr; - fFrames->getReleasingFrameParams(fromPtr, fFrameSize, - fPresentationTime, fDurationInMicroseconds); - - if (fFrameSize > fMaxSize) { - fNumTruncatedBytes = fFrameSize - fMaxSize; - fFrameSize = fMaxSize; - } - memmove(fTo, fromPtr, fFrameSize); - - fFrames->releaseNext(); -} - -////////// InterleavingFrames (implementation) ////////// - -#define MAX_FRAME_SIZE 2000 /* conservatively high */ - -class InterleavingFrameDescriptor { -public: - InterleavingFrameDescriptor() {frameDataSize = 0;} - - unsigned frameDataSize; // includes ADU descriptor and (modified) MPEG hdr - struct timeval presentationTime; - unsigned durationInMicroseconds; - unsigned char frameData[MAX_FRAME_SIZE]; // ditto -}; - -InterleavingFrames::InterleavingFrames(unsigned maxCycleSize) - : fMaxCycleSize(maxCycleSize), fNextIndexToRelease(0), - fDescriptors(new InterleavingFrameDescriptor[maxCycleSize]) { -} -InterleavingFrames::~InterleavingFrames() { - delete[] fDescriptors; -} - -Boolean InterleavingFrames::haveReleaseableFrame() { - return fDescriptors[fNextIndexToRelease].frameDataSize > 0; -} - -void InterleavingFrames::getIncomingFrameParams(unsigned char index, - unsigned char*& dataPtr, - unsigned& bytesAvailable) { - InterleavingFrameDescriptor& desc = fDescriptors[index]; - dataPtr = &desc.frameData[0]; - bytesAvailable = MAX_FRAME_SIZE; -} - -void InterleavingFrames::getReleasingFrameParams(unsigned char index, - unsigned char*& dataPtr, - unsigned& bytesInUse, - struct timeval& presentationTime, - unsigned& durationInMicroseconds) { - InterleavingFrameDescriptor& desc = fDescriptors[index]; - dataPtr = &desc.frameData[0]; - bytesInUse = desc.frameDataSize; - presentationTime = desc.presentationTime; - durationInMicroseconds = desc.durationInMicroseconds; -} - -void InterleavingFrames::setFrameParams(unsigned char index, - unsigned char icc, - unsigned char ii, - unsigned frameSize, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - InterleavingFrameDescriptor& desc = fDescriptors[index]; - desc.frameDataSize = frameSize; - desc.presentationTime = presentationTime; - desc.durationInMicroseconds = durationInMicroseconds; - - // Advance over the ADU descriptor, to get to the MPEG 'syncword': - unsigned char* ptr = &desc.frameData[0]; - (void)ADUdescriptor::getRemainingFrameSize(ptr); - - // Replace the next 11 bits with (ii,icc): - *ptr++ = ii; - *ptr &=~ 0xE0; - *ptr |= (icc<<5); -} - -void InterleavingFrames::releaseNext() { - fDescriptors[fNextIndexToRelease].frameDataSize = 0; - fNextIndexToRelease = (fNextIndexToRelease+1)%fMaxCycleSize; -} - -////////// DeinterleavingFrames (implementation) ////////// - -class DeinterleavingFrameDescriptor { -public: - DeinterleavingFrameDescriptor() {frameDataSize = 0; frameData = NULL;} - virtual ~DeinterleavingFrameDescriptor() {delete[] frameData;} - - unsigned frameDataSize; // includes ADU descriptor and (modified) MPEG hdr - struct timeval presentationTime; - unsigned durationInMicroseconds; - unsigned char* frameData; -}; - -DeinterleavingFrames::DeinterleavingFrames() - : fNextIndexToRelease(0), fHaveEndedCycle(False), - fMinIndexSeen(MAX_CYCLE_SIZE), fMaxIndexSeen(0), - fDescriptors(new DeinterleavingFrameDescriptor[MAX_CYCLE_SIZE+1]) { -} -DeinterleavingFrames::~DeinterleavingFrames() { - delete[] fDescriptors; -} - -Boolean DeinterleavingFrames::haveReleaseableFrame() { - if (!fHaveEndedCycle) { - // Check just the next frame in the sequence - return fDescriptors[fNextIndexToRelease].frameDataSize > 0; - } else { - // We've just ended a cycle, so we can skip over frames that didn't - // get filled in (due to packet loss): - if (fNextIndexToRelease < fMinIndexSeen) { - fNextIndexToRelease = fMinIndexSeen; - } - while (fNextIndexToRelease < fMaxIndexSeen - && fDescriptors[fNextIndexToRelease].frameDataSize == 0) { - ++fNextIndexToRelease; - } - if (fNextIndexToRelease >= fMaxIndexSeen) { - // No more frames are available from the cycle that we just ended, so - // clear out all previously stored frames, then make available - // the last-read frame, and return false for now: - for (unsigned i = fMinIndexSeen; i < fMaxIndexSeen; ++i) { - fDescriptors[i].frameDataSize = 0; - } - - fMinIndexSeen = MAX_CYCLE_SIZE; fMaxIndexSeen = 0; - moveIncomingFrameIntoPlace(); - - fHaveEndedCycle = False; - fNextIndexToRelease = 0; - return False; - } - - return True; - } -} - -void DeinterleavingFrames::getIncomingFrameParams(unsigned char*& dataPtr, - unsigned& bytesAvailable) { - // Use fDescriptors[MAX_CYCLE_SIZE] to store the incoming frame, - // prior to figuring out its real position: - DeinterleavingFrameDescriptor& desc = fDescriptors[MAX_CYCLE_SIZE]; - if (desc.frameData == NULL) { - // There's no buffer yet, so allocate a new one: - desc.frameData = new unsigned char[MAX_FRAME_SIZE]; - } - dataPtr = desc.frameData; - bytesAvailable = MAX_FRAME_SIZE; -} - -void DeinterleavingFrames -::getIncomingFrameParamsAfter(unsigned frameSize, - struct timeval presentationTime, - unsigned durationInMicroseconds, - unsigned char& icc, unsigned char& ii) { - DeinterleavingFrameDescriptor& desc = fDescriptors[MAX_CYCLE_SIZE]; - desc.frameDataSize = frameSize; - desc.presentationTime = presentationTime; - desc.durationInMicroseconds = durationInMicroseconds; - - // Advance over the ADU descriptor, to get to the MPEG 'syncword': - unsigned char* ptr = desc.frameData; - (void)ADUdescriptor::getRemainingFrameSize(ptr); - - // Read the next 11 bits into (ii,icc), and replace them with all-1s: - fIIlastSeen = ii = *ptr; *ptr++ = 0xFF; - icc = (*ptr&0xE0)>>5; *ptr |= 0xE0; -} - -void DeinterleavingFrames::getReleasingFrameParams(unsigned char*& dataPtr, - unsigned& bytesInUse, - struct timeval& presentationTime, - unsigned& durationInMicroseconds) { - DeinterleavingFrameDescriptor& desc = fDescriptors[fNextIndexToRelease]; - dataPtr = desc.frameData; - bytesInUse = desc.frameDataSize; - presentationTime = desc.presentationTime; - durationInMicroseconds = desc.durationInMicroseconds; -} - -void DeinterleavingFrames::moveIncomingFrameIntoPlace() { - DeinterleavingFrameDescriptor& fromDesc = fDescriptors[MAX_CYCLE_SIZE]; - DeinterleavingFrameDescriptor& toDesc = fDescriptors[fIIlastSeen]; - - toDesc.frameDataSize = fromDesc.frameDataSize; - toDesc.presentationTime = fromDesc.presentationTime; - - // Move the data pointer into place by swapping the data pointers: - unsigned char* tmp = toDesc.frameData; - toDesc.frameData = fromDesc.frameData; - fromDesc.frameData = tmp; - - if (fIIlastSeen < fMinIndexSeen) { - fMinIndexSeen = fIIlastSeen; - } - if (fIIlastSeen + 1 > fMaxIndexSeen) { - fMaxIndexSeen = fIIlastSeen + 1; - } -} - -void DeinterleavingFrames::releaseNext() { - fDescriptors[fNextIndexToRelease].frameDataSize = 0; - fNextIndexToRelease = (fNextIndexToRelease+1)%MAX_CYCLE_SIZE; -} - -void DeinterleavingFrames::startNewCycle() { - fHaveEndedCycle = True; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3AudioFileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3AudioFileServerMediaSubsession.cpp deleted file mode 100644 index 5ad66b78f0e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3AudioFileServerMediaSubsession.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MP3 audio file. -// (Actually, any MPEG-1 or MPEG-2 audio file should work.) -// Implementation - -#include "MP3AudioFileServerMediaSubsession.hh" -#include "MPEG1or2AudioRTPSink.hh" -#include "MP3ADURTPSink.hh" -#include "MP3FileSource.hh" -#include "MP3ADU.hh" - -MP3AudioFileServerMediaSubsession* MP3AudioFileServerMediaSubsession -::createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource, - Boolean generateADUs, Interleaving* interleaving) { - return new MP3AudioFileServerMediaSubsession(env, fileName, reuseFirstSource, - generateADUs, interleaving); -} - -MP3AudioFileServerMediaSubsession -::MP3AudioFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource, - Boolean generateADUs, - Interleaving* interleaving) - : FileServerMediaSubsession(env, fileName, reuseFirstSource), - fGenerateADUs(generateADUs), fInterleaving(interleaving), fFileDuration(0.0) { -} - -MP3AudioFileServerMediaSubsession -::~MP3AudioFileServerMediaSubsession() { - delete fInterleaving; -} - -void MP3AudioFileServerMediaSubsession -::seekStreamSource(FramedSource* inputSource, float seekNPT) { - MP3FileSource* mp3Source; - if (fGenerateADUs) { - // "inputSource" is a filter; use its input source instead. - ADUFromMP3Source* filter; - if (fInterleaving != NULL) { - // There's another filter as well. - filter = (ADUFromMP3Source*)(((FramedFilter*)inputSource)->inputSource()); - } else { - filter = (ADUFromMP3Source*)inputSource; - } - filter->resetInput(); // because we're about to seek within its source - mp3Source = (MP3FileSource*)(filter->inputSource()); - } else if (fFileDuration > 0.0) { - // There are a pair of filters - MP3->ADU and ADU->MP3 - in front of the - // original MP3 source: - MP3FromADUSource* filter2 = (MP3FromADUSource*)inputSource; - ADUFromMP3Source* filter1 = (ADUFromMP3Source*)(filter2->inputSource()); - filter1->resetInput(); // because we're about to seek within its source - mp3Source = (MP3FileSource*)(filter1->inputSource()); - } else { - // "inputSource" is the original MP3 source: - mp3Source = (MP3FileSource*)inputSource; - } - - mp3Source->seekWithinFile(seekNPT); -} - -void MP3AudioFileServerMediaSubsession -::setStreamSourceScale(FramedSource* inputSource, float scale) { - int iScale = (int)scale; - MP3FileSource* mp3Source; - ADUFromMP3Source* aduSource = NULL; - if (fGenerateADUs) { - if (fInterleaving != NULL) { - // There's an interleaving filter in front. - aduSource = (ADUFromMP3Source*)(((FramedFilter*)inputSource)->inputSource()); - } else { - aduSource = (ADUFromMP3Source*)inputSource; - } - mp3Source = (MP3FileSource*)(aduSource->inputSource()); - } else if (fFileDuration > 0.0) { - // There are a pair of filters - MP3->ADU and ADU->MP3 - in front of the - // original MP3 source. So, go back one, to reach the ADU source: - aduSource = (ADUFromMP3Source*)(((FramedFilter*)inputSource)->inputSource()); - - // Then, go back one more, to reach the MP3 source: - mp3Source = (MP3FileSource*)(aduSource->inputSource()); - } else return; // the stream is not scalable - - aduSource->setScaleFactor(iScale); - mp3Source->setPresentationTimeScale(iScale); -} - -FramedSource* MP3AudioFileServerMediaSubsession -::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) { - estBitrate = 128; // kbps, estimate - - FramedSource* streamSource; - do { - MP3FileSource* mp3Source; - streamSource = mp3Source = MP3FileSource::createNew(envir(), fFileName); - if (streamSource == NULL) break; - fFileDuration = mp3Source->filePlayTime(); - - if (fGenerateADUs) { - // Add a filter that converts the source MP3s to ADUs: - streamSource = ADUFromMP3Source::createNew(envir(), streamSource); - if (streamSource == NULL) break; - - if (fInterleaving != NULL) { - // Add another filter that interleaves the ADUs before packetizing: - streamSource = MP3ADUinterleaver::createNew(envir(), *fInterleaving, - streamSource); - if (streamSource == NULL) break; - } - } else if (fFileDuration > 0.0) { - // Because this is a seekable file, insert a pair of filters: one that - // converts the input MP3 stream to ADUs; another that converts these - // ADUs back to MP3. This allows us to seek within the input stream without - // tripping over the MP3 'bit reservoir': - streamSource = ADUFromMP3Source::createNew(envir(), streamSource); - if (streamSource == NULL) break; - - streamSource = MP3FromADUSource::createNew(envir(), streamSource); - if (streamSource == NULL) break; - } - } while (0); - - return streamSource; -} - -RTPSink* MP3AudioFileServerMediaSubsession -::createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* /*inputSource*/) { - if (fGenerateADUs) { - return MP3ADURTPSink::createNew(envir(), rtpGroupsock, - rtpPayloadTypeIfDynamic); - } else { - return MPEG1or2AudioRTPSink::createNew(envir(), rtpGroupsock); - } -} - -void MP3AudioFileServerMediaSubsession::testScaleFactor(float& scale) { - if (fFileDuration <= 0.0) { - // The file is non-seekable, so is probably a live input source. - // We don't support scale factors other than 1 - scale = 1; - } else { - // We support any integral scale >= 1 - int iScale = (int)(scale + 0.5); // round - if (iScale < 1) iScale = 1; - scale = (float)iScale; - } -} - -float MP3AudioFileServerMediaSubsession::duration() const { - return fFileDuration; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3FileSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3FileSource.cpp deleted file mode 100644 index 10f908e57bc..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3FileSource.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 File Sources -// Implementation - -#include "MP3FileSource.hh" -#include "MP3StreamState.hh" -#include "InputFile.hh" - -////////// MP3FileSource ////////// - -MP3FileSource::MP3FileSource(UsageEnvironment& env, FILE* fid) - : FramedFileSource(env, fid), - fStreamState(new MP3StreamState(env)) { -} - -MP3FileSource::~MP3FileSource() { - delete fStreamState; -} - -char const* MP3FileSource::MIMEtype() const { - return "audio/MPEG"; -} - -MP3FileSource* MP3FileSource::createNew(UsageEnvironment& env, char const* fileName) { - MP3FileSource* newSource = NULL; - - do { - FILE* fid; - - fid = OpenInputFile(env, fileName); - if (fid == NULL) break; - - newSource = new MP3FileSource(env, fid); - if (newSource == NULL) break; - - unsigned fileSize = (unsigned)GetFileSize(fileName, fid); - newSource->assignStream(fid, fileSize); - if (!newSource->initializeStream()) break; - - return newSource; - } while (0); - - Medium::close(newSource); - return NULL; -} - -float MP3FileSource::filePlayTime() const { - return fStreamState->filePlayTime(); -} - -void MP3FileSource::setPresentationTimeScale(unsigned scale) { - fStreamState->setPresentationTimeScale(scale); -} - -void MP3FileSource::seekWithinFile(float seekNPT) { - fStreamState->seekWithinFile(seekNPT); -} - -void MP3FileSource::getAttributes() const { - char buffer[200]; - fStreamState->getAttributes(buffer, sizeof buffer); - envir().setResultMsg(buffer); -} - -void MP3FileSource::doGetNextFrame() { - if (!doGetNextFrame1()) { - handleClosure(this); - return; - } - - // Switch to another task: -#if defined(__WIN32__) || defined(_WIN32) - // HACK: liveCaster/lc uses an implementation of scheduleDelayedTask() - // that performs very badly (chewing up lots of CPU time, apparently polling) - // on Windows. Until this is fixed, we just call our "afterGetting()" - // function directly. This avoids infinite recursion, as long as our sink - // is discontinuous, which is the case for the RTP sink that liveCaster/lc - // uses. ##### - afterGetting(this); -#else - nextTask() = envir().taskScheduler().scheduleDelayedTask(0, - (TaskFunc*)afterGetting, this); -#endif -} - -Boolean MP3FileSource::doGetNextFrame1() { - if (!fHaveJustInitialized) { - if (fStreamState->findNextHeader(fPresentationTime) == 0) return False; - } else { - fPresentationTime = fFirstFramePresentationTime; - fHaveJustInitialized = False; - } - - if (!fStreamState->readFrame(fTo, fMaxSize, fFrameSize, fDurationInMicroseconds)) { - char tmp[200]; - sprintf(tmp, - "Insufficient buffer size %d for reading MPEG audio frame (needed %d)\n", - fMaxSize, fFrameSize); - envir().setResultMsg(tmp); - fFrameSize = fMaxSize; - return False; - } - - return True; -} - -void MP3FileSource::assignStream(FILE* fid, unsigned fileSize) { - fStreamState->assignStream(fid, fileSize); -} - - -Boolean MP3FileSource::initializeStream() { - // Make sure the file has an appropriate header near the start: - if (fStreamState->findNextHeader(fFirstFramePresentationTime) == 0) { - envir().setResultMsg("not an MPEG audio file"); - return False; - } - - fStreamState->checkForXingHeader(); // in case this is a VBR file - - fHaveJustInitialized = True; - // Hack: It's possible that our environment's 'result message' has been - // reset within this function, so set it again to our name now: - envir().setResultMsg(name()); - return True; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3HTTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3HTTPSource.cpp deleted file mode 100644 index 7c4f77d50cb..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3HTTPSource.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 HTTP Sources -// Implementation - -#include "MP3HTTPSource.hh" -#include "GroupsockHelper.hh" -#include "MP3StreamState.hh" - -MP3HTTPSource* MP3HTTPSource::createNew(UsageEnvironment& env, - NetAddress const& remoteAddress, - Port remotePort, - char const* remoteHostName, - char const* fileName) { - int ourSocket = -1; - MP3HTTPSource* newSource = NULL; - - do { - // Create a stream socket for this source. - // Note: We don't make the socket non-blocking, because we want - // to read from it synchronously (as we do with real file sources) - ourSocket = setupStreamSocket(env, 0, False); - if (ourSocket < 0) break; - - // Connect to the remote endpoint: - MAKE_SOCKADDR_IN(remoteName, *(unsigned*)(remoteAddress.data()), remotePort.num()); - if (connect(ourSocket, (struct sockaddr*)&remoteName, sizeof remoteName) - != 0) { - env.setResultErrMsg("connect() failed: "); - break; - } - - // Make sure we have a big receive buffer: - if (!increaseReceiveBufferTo(env, ourSocket, 100*1024)) break; - - // Try to make the new socket into a FILE*: - unsigned streamLength = 0; //##### - FILE* fid = NULL; -#if !defined(IMN_PIM) && !defined(CRIS) && !defined(_WIN32_WCE) - fid = fdopen(ourSocket, "r+b"); -#endif - if (fid == NULL) { - // HACK HACK HACK ##### - // We couldn't convert the socket to a FILE*; perhaps this is Windoze? - // Instead, tell the low-level to read it directly as a socket: - long ourSocket_long = (long)ourSocket; - fid = (FILE*)ourSocket_long; - streamLength = (unsigned)(-1); - } - - newSource = new MP3HTTPSource(env, fid); - if (newSource == NULL) break; - - newSource->assignStream(fid, streamLength); - - // Write the HTTP 'GET' command: - newSource->writeGetCmd(remoteHostName, ntohs(remotePort.num()), - fileName); - - // Now read the first frame header, to finish initializing the stream: - if (!newSource->initializeStream()) break; - - return newSource; - } while (0); - - if (ourSocket != -1) ::closeSocket(ourSocket); - Medium::close(newSource); - return NULL; -} - -MP3HTTPSource::MP3HTTPSource(UsageEnvironment& env, FILE* fid) - : MP3FileSource(env, fid) { -} - -MP3HTTPSource::~MP3HTTPSource() { -} - -void MP3HTTPSource::writeGetCmd(char const* hostName, unsigned portNum, - char const* fileName) { - streamState()->writeGetCmd(hostName, portNum, fileName); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3Internals.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3Internals.cpp deleted file mode 100644 index 1593023414f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3Internals.cpp +++ /dev/null @@ -1,809 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 internal implementation details -// Implementation - -#include "MP3InternalsHuffman.hh" - -#include -#include -#include -#include - -// This is crufty old code that needs to be cleaned up ##### - -static unsigned live_tabsel[2][3][16] = { - { {32,32,64,96,128,160,192,224,256,288,320,352,384,416,448,448}, - {32,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,384}, - {32,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,320} }, - - { {32,32,48,56,64,80,96,112,128,144,160,176,192,224,256,256}, - {8,8,16,24,32,40,48,56,64,80,96,112,128,144,160,160}, - {8,8,16,24,32,40,48,56,64,80,96,112,128,144,160,160} } -}; -/* Note: live_tabsel[*][*][0 or 15] shouldn't occur; use dummy values there */ - -static long live_freqs[] -= { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000, 0 }; - -struct bandInfoStruct { - int longIdx[23]; - int longDiff[22]; - int shortIdx[14]; - int shortDiff[13]; -}; - -static struct bandInfoStruct const bandInfo[7] = { -/* MPEG 1.0 */ - { {0,4,8,12,16,20,24,30,36,44,52,62,74, 90,110,134,162,196,238,288,342,418,576}, - {4,4,4,4,4,4,6,6,8, 8,10,12,16,20,24,28,34,42,50,54, 76,158}, - {0,4*3,8*3,12*3,16*3,22*3,30*3,40*3,52*3,66*3, 84*3,106*3,136*3,192*3}, - {4,4,4,4,6,8,10,12,14,18,22,30,56} } , - - { {0,4,8,12,16,20,24,30,36,42,50,60,72, 88,106,128,156,190,230,276,330,384,576}, - {4,4,4,4,4,4,6,6,6, 8,10,12,16,18,22,28,34,40,46,54, 54,192}, - {0,4*3,8*3,12*3,16*3,22*3,28*3,38*3,50*3,64*3, 80*3,100*3,126*3,192*3}, - {4,4,4,4,6,6,10,12,14,16,20,26,66} } , - - { {0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576} , - {4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102, 26} , - {0,4*3,8*3,12*3,16*3,22*3,30*3,42*3,58*3,78*3,104*3,138*3,180*3,192*3} , - {4,4,4,4,6,8,12,16,20,26,34,42,12} } , - -/* MPEG 2.0 */ - { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, - {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 } , - {0,4*3,8*3,12*3,18*3,24*3,32*3,42*3,56*3,74*3,100*3,132*3,174*3,192*3} , - {4,4,4,6,6,8,10,14,18,26,32,42,18 } } , - - { {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576}, - {6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,52,64,70,76,36 } , - {0,4*3,8*3,12*3,18*3,26*3,36*3,48*3,62*3,80*3,104*3,136*3,180*3,192*3} , - {4,4,4,6,8,10,12,14,18,24,32,44,12 } } , - - { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, - {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 }, - {0,4*3,8*3,12*3,18*3,26*3,36*3,48*3,62*3,80*3,104*3,134*3,174*3,192*3}, - {4,4,4,6,8,10,12,14,18,24,30,40,18 } } , - -/* MPEG 2.5, wrong! table (it's just a copy of MPEG 2.0/44.1kHz) */ - { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, - {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 } , - {0,4*3,8*3,12*3,18*3,24*3,32*3,42*3,56*3,74*3,100*3,132*3,174*3,192*3} , - {4,4,4,6,6,8,10,14,18,26,32,42,18 } } , -}; - -unsigned int n_slen2[512]; /* MPEG 2.0 slen for 'normal' mode */ -unsigned int i_slen2[256]; /* MPEG 2.0 slen for intensity stereo */ - -#define MPG_MD_MONO 3 - - -////////// MP3FrameParams ////////// - -MP3FrameParams::MP3FrameParams() - : bv(frameBytes, 0, sizeof frameBytes) /* by default */ { - oldHdr = firstHdr = 0; - - static Boolean doneInit = False; - if (doneInit) return; - doneInit = True; - - int i,j,k,l; - - for (i=0;i<5;i++) { - for (j=0;j<6;j++) { - for (k=0;k<6;k++) { - int n = k + j * 6 + i * 36; - i_slen2[n] = i|(j<<3)|(k<<6)|(3<<12); - } - } - } - for (i=0;i<4;i++) { - for (j=0;j<4;j++) { - for (k=0;k<4;k++) { - int n = k + j * 4 + i * 16; - i_slen2[n+180] = i|(j<<3)|(k<<6)|(4<<12); - } - } - } - for (i=0;i<4;i++) { - for (j=0;j<3;j++) { - int n = j + i * 3; - i_slen2[n+244] = i|(j<<3) | (5<<12); - n_slen2[n+500] = i|(j<<3) | (2<<12) | (1<<15); - } - } - - for (i=0;i<5;i++) { - for (j=0;j<5;j++) { - for (k=0;k<4;k++) { - for (l=0;l<4;l++) { - int n = l + k * 4 + j * 16 + i * 80; - n_slen2[n] = i|(j<<3)|(k<<6)|(l<<9)|(0<<12); - } - } - } - } - for (i=0;i<5;i++) { - for (j=0;j<5;j++) { - for (k=0;k<4;k++) { - int n = k + j * 4 + i * 20; - n_slen2[n+400] = i|(j<<3)|(k<<6)|(1<<12); - } - } - } -} - -MP3FrameParams::~MP3FrameParams() { -} - -void MP3FrameParams::setParamsFromHeader() { - if (hdr & (1<<20)) { - isMPEG2 = (hdr & (1<<19)) ? 0x0 : 0x1; - isMPEG2_5 = 0; - } - else { - isMPEG2 = 1; - isMPEG2_5 = 1; - } - - layer = 4-((hdr>>17)&3); - if (layer == 4) layer = 3; // layer==4 is not allowed - bitrateIndex = ((hdr>>12)&0xf); - - if (isMPEG2_5) { - samplingFreqIndex = ((hdr>>10)&0x3) + 6; - } else { - samplingFreqIndex = ((hdr>>10)&0x3) + (isMPEG2*3); - } - - hasCRC = ((hdr>>16)&0x1)^0x1; - - padding = ((hdr>>9)&0x1); - extension = ((hdr>>8)&0x1); - mode = ((hdr>>6)&0x3); - mode_ext = ((hdr>>4)&0x3); - copyright = ((hdr>>3)&0x1); - original = ((hdr>>2)&0x1); - emphasis = hdr & 0x3; - - stereo = (mode == MPG_MD_MONO) ? 1 : 2; - - if (((hdr>>10)&0x3) == 0x3) { -#ifdef DEBUG_ERRORS - fprintf(stderr,"Stream error - hdr: 0x%08x\n", hdr); -#endif - } - - bitrate = live_tabsel[isMPEG2][layer-1][bitrateIndex]; - samplingFreq = live_freqs[samplingFreqIndex]; - isStereo = (stereo > 1); - isFreeFormat = (bitrateIndex == 0); - frameSize - = ComputeFrameSize(bitrate, samplingFreq, padding, isMPEG2, layer); - sideInfoSize = computeSideInfoSize(); - } - -unsigned MP3FrameParams::computeSideInfoSize() { - unsigned size; - - if (isMPEG2) { - size = isStereo ? 17 : 9; - } else { - size = isStereo ? 32 : 17; - } - - if (hasCRC) { - size += 2; - } - - return size; -} - -unsigned ComputeFrameSize(unsigned bitrate, unsigned samplingFreq, - Boolean usePadding, Boolean isMPEG2, - unsigned char layer) { - if (samplingFreq == 0) return 0; - unsigned const bitrateMultiplier = (layer == 1) ? 12000*4 : 144000; - unsigned framesize; - - framesize = bitrate*bitrateMultiplier; - framesize /= samplingFreq< allowedNumBits) { - /* We need to shorten one or both fields */ - unsigned truncation = p23L0 + p23L1 - allowedNumBits; -#ifdef TRUNC_FAIRLY - p23L0Trunc = (truncation*p23L0)/(p23L0 + p23L1); - p23L1Trunc = truncation - p23L0Trunc; -#endif -#if defined(TRUNC_FAVOR0) || defined(TRUNC_ONLY0) - p23L1Trunc = (truncation>p23L1) ? p23L1 : truncation; - p23L0Trunc = truncation - p23L1Trunc; -#endif -#if defined(TRUNC_FAVOR1) || defined(TRUNC_ONLY1) - p23L0Trunc = (truncation>p23L0) ? p23L0 : truncation; - p23L1Trunc = truncation - p23L0Trunc; -#endif - } - - /* ASSERT: (p23L0Trunc <= p23L0) && (p23l1Trunc <= p23L1) */ - p23L0 -= p23L0Trunc; p23L1 -= p23L1Trunc; -#ifdef DEBUG - fprintf(stderr, "updateSideInfoSizes (allowed: %d): %d->%d, %d->%d\n", allowedNumBits, p23L0+p23L0Trunc, p23L0, p23L1+p23L1Trunc, p23L1); -#endif - - // The truncations computed above are still estimates. We need to - // adjust them so that the new fields will continue to end on - // Huffman-encoded sample boundaries: - updateSideInfoForHuffman(sideInfo, isMPEG2, mainDataPtr, - p23L0, p23L1, - part23Length0a, part23Length0aTruncation, - part23Length0b, part23Length0bTruncation, - part23Length1a, part23Length1aTruncation, - part23Length1b, part23Length1bTruncation); - p23L0 = part23Length0a + part23Length0b; - p23L1 = part23Length1a + part23Length1b; - - sideInfo.ch[0].gr[0].part2_3_length = p23L0; - sideInfo.ch[0].gr[1].part2_3_length = p23L1; - part23Length0bTruncation - += sideInfo.ch[1].gr[0].part2_3_length; /* allow for stereo */ - sideInfo.ch[1].gr[0].part2_3_length = 0; /* output mono */ - sideInfo.ch[1].gr[1].part2_3_length = 0; /* output mono */ - - return p23L0 + p23L1; -} - - -Boolean GetADUInfoFromMP3Frame(unsigned char const* framePtr, - unsigned totFrameSize, - unsigned& hdr, unsigned& frameSize, - MP3SideInfo& sideInfo, unsigned& sideInfoSize, - unsigned& backpointer, unsigned& aduSize) { - if (totFrameSize < 4) return False; // there's not enough data - - MP3FrameParams fr; - fr.hdr = ((unsigned)framePtr[0] << 24) | ((unsigned)framePtr[1] << 16) - | ((unsigned)framePtr[2] << 8) | (unsigned)framePtr[3]; - fr.setParamsFromHeader(); - fr.setBytePointer(framePtr + 4, totFrameSize - 4); // skip hdr - - frameSize = 4 + fr.frameSize; - - if (fr.layer != 3) { - // Special case for non-layer III frames - backpointer = 0; - sideInfoSize = 0; - aduSize = fr.frameSize; - return True; - } - - sideInfoSize = fr.sideInfoSize; - if (totFrameSize < 4 + sideInfoSize) return False; // not enough data - - fr.getSideInfo(sideInfo); - - hdr = fr.hdr; - backpointer = sideInfo.main_data_begin; - unsigned numBits = sideInfo.ch[0].gr[0].part2_3_length; - numBits += sideInfo.ch[0].gr[1].part2_3_length; - numBits += sideInfo.ch[1].gr[0].part2_3_length; - numBits += sideInfo.ch[1].gr[1].part2_3_length; - aduSize = (numBits+7)/8; -#ifdef DEBUG - fprintf(stderr, "mp3GetADUInfoFromFrame: hdr: %08x, frameSize: %d, part2_3_lengths: %d,%d,%d,%d, aduSize: %d, backpointer: %d\n", hdr, frameSize, sideInfo.ch[0].gr[0].part2_3_length, sideInfo.ch[0].gr[1].part2_3_length, sideInfo.ch[1].gr[0].part2_3_length, sideInfo.ch[1].gr[1].part2_3_length, aduSize, backpointer); -#endif - - return True; -} - - -static void getSideInfo1(MP3FrameParams& fr, MP3SideInfo& si, - int stereo, int ms_stereo, long sfreq, - int /*single*/) { - int ch, gr; -#if 0 - int powdiff = (single == 3) ? 4 : 0; -#endif - - /* initialize all four "part2_3_length" fields to zero: */ - si.ch[0].gr[0].part2_3_length = 0; si.ch[1].gr[0].part2_3_length = 0; - si.ch[0].gr[1].part2_3_length = 0; si.ch[1].gr[1].part2_3_length = 0; - - si.main_data_begin = fr.getBits(9); - if (stereo == 1) - si.private_bits = fr.getBits(5); - else - si.private_bits = fr.getBits(3); - - for (ch=0; ch win-sw-flag = 0 */ - gr_info.window_switching_flag = fr.get1Bit(); - if (gr_info.window_switching_flag) { - int i; - gr_info.block_type = fr.getBits(2); - gr_info.mixed_block_flag = fr.get1Bit(); - gr_info.table_select[0] = fr.getBits(5); - gr_info.table_select[1] = fr.getBits(5); - /* - * table_select[2] not needed, because there is no region2, - * but to satisfy some verifications tools we set it either. - */ - gr_info.table_select[2] = 0; - for (i=0;i<3;i++) { - gr_info.subblock_gain[i] = fr.getBits(3); - gr_info.full_gain[i] - = gr_info.pow2gain + ((gr_info.subblock_gain[i])<<3); - } - -#ifdef DEBUG_ERRORS - if (gr_info.block_type == 0) { - fprintf(stderr,"Blocktype == 0 and window-switching == 1 not allowed.\n"); - } -#endif - /* region_count/start parameters are implicit in this case. */ - gr_info.region1start = 36>>1; - gr_info.region2start = 576>>1; - } - else - { - int i,r0c,r1c; - for (i=0; i<3; i++) { - gr_info.table_select[i] = fr.getBits(5); - } - r0c = gr_info.region0_count = fr.getBits(4); - r1c = gr_info.region1_count = fr.getBits(3); - gr_info.region1start = bandInfo[sfreq].longIdx[r0c+1] >> 1 ; - gr_info.region2start = bandInfo[sfreq].longIdx[r0c+1+r1c+1] >> 1; - gr_info.block_type = 0; - gr_info.mixed_block_flag = 0; - } - gr_info.preflag = fr.get1Bit(); - gr_info.scalefac_scale = fr.get1Bit(); - gr_info.count1table_select = fr.get1Bit(); - } - } -} - -static void getSideInfo2(MP3FrameParams& fr, MP3SideInfo& si, - int stereo, int ms_stereo, long sfreq, - int /*single*/) { - int ch; -#if 0 - int powdiff = (single == 3) ? 4 : 0; -#endif - - /* initialize all four "part2_3_length" fields to zero: */ - si.ch[0].gr[0].part2_3_length = 0; si.ch[1].gr[0].part2_3_length = 0; - si.ch[0].gr[1].part2_3_length = 0; si.ch[1].gr[1].part2_3_length = 0; - - si.main_data_begin = fr.getBits(8); - if (stereo == 1) - si.private_bits = fr.get1Bit(); - else - si.private_bits = fr.getBits(2); - - for (ch=0; ch win-sw-flag = 0 */ - gr_info.window_switching_flag = fr.get1Bit(); - if (gr_info.window_switching_flag) { - int i; - gr_info.block_type = fr.getBits(2); - gr_info.mixed_block_flag = fr.get1Bit(); - gr_info.table_select[0] = fr.getBits(5); - gr_info.table_select[1] = fr.getBits(5); - /* - * table_select[2] not needed, because there is no region2, - * but to satisfy some verifications tools we set it either. - */ - gr_info.table_select[2] = 0; - for (i=0;i<3;i++) { - gr_info.subblock_gain[i] = fr.getBits(3); - gr_info.full_gain[i] - = gr_info.pow2gain + ((gr_info.subblock_gain[i])<<3); - } - -#ifdef DEBUG_ERRORS - if (gr_info.block_type == 0) { - fprintf(stderr,"Blocktype == 0 and window-switching == 1 not allowed.\n"); - } -#endif - /* region_count/start parameters are implicit in this case. */ -/* check this again! */ - if (gr_info.block_type == 2) - gr_info.region1start = 36>>1; - else { - gr_info.region1start = 54>>1; - } - gr_info.region2start = 576>>1; - } - else - { - int i,r0c,r1c; - for (i=0; i<3; i++) { - gr_info.table_select[i] = fr.getBits(5); - } - r0c = gr_info.region0_count = fr.getBits(4); - r1c = gr_info.region1_count = fr.getBits(3); - gr_info.region1start = bandInfo[sfreq].longIdx[r0c+1] >> 1 ; - gr_info.region2start = bandInfo[sfreq].longIdx[r0c+1+r1c+1] >> 1; - gr_info.block_type = 0; - gr_info.mixed_block_flag = 0; - } - gr_info.scalefac_scale = fr.get1Bit(); - gr_info.count1table_select = fr.get1Bit(); - } -} - - -#define MPG_MD_JOINT_STEREO 1 - -void MP3FrameParams::getSideInfo(MP3SideInfo& si) { - // First skip over the CRC if present: - if (hasCRC) getBits(16); - - int single = -1; - int ms_stereo, i_stereo; - int sfreq = samplingFreqIndex; - - if (stereo == 1) { - single = 0; - } - - ms_stereo = (mode == MPG_MD_JOINT_STEREO) && (mode_ext & 0x2); - i_stereo = (mode == MPG_MD_JOINT_STEREO) && (mode_ext & 0x1); - - if (isMPEG2) { - getSideInfo2(*this, si, stereo, ms_stereo, sfreq, single); - } else { - getSideInfo1(*this, si, stereo, ms_stereo, sfreq, single); - } -} - -static void putSideInfo1(BitVector& bv, - MP3SideInfo const& si, Boolean isStereo) { - int ch, gr, i; - int stereo = isStereo ? 2 : 1; - - bv.putBits(si.main_data_begin,9); - if (stereo == 1) - bv.putBits(si.private_bits, 5); - else - bv.putBits(si.private_bits, 3); - - for (ch=0; ch= bitrate) - return i; - } - - // "bitrate" was larger than any possible, so return the largest possible: - return 14; -} - -static void outputHeader(unsigned char* toPtr, unsigned hdr) { - toPtr[0] = (unsigned char)(hdr>>24); - toPtr[1] = (unsigned char)(hdr>>16); - toPtr[2] = (unsigned char)(hdr>>8); - toPtr[3] = (unsigned char)(hdr); -} - -static void assignADUBackpointer(MP3FrameParams const& fr, - unsigned aduSize, - MP3SideInfo& sideInfo, - unsigned& availableBytesForBackpointer) { - // Give the ADU as large a backpointer as possible: - unsigned maxBackpointerSize = fr.isMPEG2 ? 255 : 511; - - unsigned backpointerSize = availableBytesForBackpointer; - if (backpointerSize > maxBackpointerSize) { - backpointerSize = maxBackpointerSize; - } - - // Store the new backpointer now: - sideInfo.main_data_begin = backpointerSize; - - // Figure out how many bytes are available for the *next* ADU's backpointer: - availableBytesForBackpointer - = backpointerSize + fr.frameSize - fr.sideInfoSize ; - if (availableBytesForBackpointer < aduSize) { - availableBytesForBackpointer = 0; - } else { - availableBytesForBackpointer -= aduSize; - } -} - -unsigned TranscodeMP3ADU(unsigned char const* fromPtr, unsigned fromSize, - unsigned toBitrate, - unsigned char* toPtr, unsigned toMaxSize, - unsigned& availableBytesForBackpointer) { - // Begin by parsing the input ADU's parameters: - unsigned hdr, inFrameSize, inSideInfoSize, backpointer, inAduSize; - MP3SideInfo sideInfo; - if (!GetADUInfoFromMP3Frame(fromPtr, fromSize, - hdr, inFrameSize, sideInfo, inSideInfoSize, - backpointer, inAduSize)) { - return 0; - } - fromPtr += (4+inSideInfoSize); // skip to 'main data' - - // Alter the 4-byte MPEG header to reflect the output ADU: - // (different bitrate; mono; no CRC) - Boolean isMPEG2 = ((hdr&0x00080000) == 0); - unsigned toBitrateIndex = MP3BitrateToBitrateIndex(toBitrate, isMPEG2); - hdr &=~ 0xF000; hdr |= (toBitrateIndex<<12); // set bitrate index - hdr |= 0x10200; // turn on !error-prot and padding bits - hdr &=~ 0xC0; hdr |= 0xC0; // set mode to 3 (mono) - - // Set up the rest of the parameters of the new ADU: - MP3FrameParams outFr; - outFr.hdr = hdr; - outFr.setParamsFromHeader(); - - // Figure out how big to make the output ADU: - unsigned inAveAduSize = inFrameSize - inSideInfoSize; - unsigned outAveAduSize = outFr.frameSize - outFr.sideInfoSize; - unsigned desiredOutAduSize /*=inAduSize*outAveAduSize/inAveAduSize*/ - = (2*inAduSize*outAveAduSize + inAveAduSize)/(2*inAveAduSize); - // this rounds to the nearest integer - - if (toMaxSize < (4 + outFr.sideInfoSize)) return 0; - unsigned maxOutAduSize = toMaxSize - (4 + outFr.sideInfoSize); - if (desiredOutAduSize > maxOutAduSize) { - desiredOutAduSize = maxOutAduSize; - } - - // Figure out the new sizes of the various 'part23 lengths', - // and how much they are truncated: - unsigned part23Length0a, part23Length0aTruncation; - unsigned part23Length0b, part23Length0bTruncation; - unsigned part23Length1a, part23Length1aTruncation; - unsigned part23Length1b, part23Length1bTruncation; - unsigned numAduBits - = updateSideInfoSizes(sideInfo, outFr.isMPEG2, - fromPtr, 8*desiredOutAduSize, - part23Length0a, part23Length0aTruncation, - part23Length0b, part23Length0bTruncation, - part23Length1a, part23Length1aTruncation, - part23Length1b, part23Length1bTruncation); -#ifdef DEBUG -fprintf(stderr, "shrinkage %d->%d [(%d,%d),(%d,%d)] (trunc: [(%d,%d),(%d,%d)]) {%d}\n", inAduSize, (numAduBits+7)/8, - part23Length0a, part23Length0b, part23Length1a, part23Length1b, - part23Length0aTruncation, part23Length0bTruncation, - part23Length1aTruncation, part23Length1bTruncation, - maxOutAduSize); -#endif - unsigned actualOutAduSize = (numAduBits+7)/8; - - // Give the new ADU an appropriate 'backpointer': - assignADUBackpointer(outFr, actualOutAduSize, sideInfo, availableBytesForBackpointer); - - ///// Now output the new ADU: - - // 4-byte header - outputHeader(toPtr, hdr); toPtr += 4; - - // side info - PutMP3SideInfoIntoFrame(sideInfo, outFr, toPtr); toPtr += outFr.sideInfoSize; - - // 'main data', using the new lengths - unsigned toBitOffset = 0; - unsigned fromBitOffset = 0; - - /* rebuild portion 0a: */ - memmove(toPtr, fromPtr, (part23Length0a+7)/8); - toBitOffset += part23Length0a; - fromBitOffset += part23Length0a + part23Length0aTruncation; - - /* rebuild portion 0b: */ - shiftBits(toPtr, toBitOffset, fromPtr, fromBitOffset, part23Length0b); - toBitOffset += part23Length0b; - fromBitOffset += part23Length0b + part23Length0bTruncation; - - /* rebuild portion 1a: */ - shiftBits(toPtr, toBitOffset, fromPtr, fromBitOffset, part23Length1a); - toBitOffset += part23Length1a; - fromBitOffset += part23Length1a + part23Length1aTruncation; - - /* rebuild portion 1b: */ - shiftBits(toPtr, toBitOffset, fromPtr, fromBitOffset, part23Length1b); - toBitOffset += part23Length1b; - - /* zero out any remaining bits (probably unnecessary, but...) */ - unsigned char const zero = '\0'; - shiftBits(toPtr, toBitOffset, &zero, 0, - actualOutAduSize*8 - numAduBits); - - return 4 + outFr.sideInfoSize + actualOutAduSize; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3Internals.hh b/mythtv/libs/libmythlivemedia/liveMedia/MP3Internals.hh deleted file mode 100644 index 7e0e58600cc..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3Internals.hh +++ /dev/null @@ -1,143 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 internal implementation details -// C++ header - -#ifndef _MP3_INTERNALS_HH -#define _MP3_INTERNALS_HH - -#ifndef _BOOLEAN_HH -#include "Boolean.hh" -#endif -#ifndef _BIT_VECTOR_HH -#include "BitVector.hh" -#endif - -typedef struct MP3SideInfo { - unsigned main_data_begin; - unsigned private_bits; - typedef struct gr_info_s { - int scfsi; - unsigned part2_3_length; - unsigned big_values; - unsigned global_gain; - unsigned scalefac_compress; - unsigned window_switching_flag; - unsigned block_type; - unsigned mixed_block_flag; - unsigned table_select[3]; - unsigned region0_count; - unsigned region1_count; - unsigned subblock_gain[3]; - unsigned maxband[3]; - unsigned maxbandl; - unsigned maxb; - unsigned region1start; - unsigned region2start; - unsigned preflag; - unsigned scalefac_scale; - unsigned count1table_select; - double *full_gain[3]; - double *pow2gain; - } gr_info_s_t; - struct { - gr_info_s_t gr[2]; - } ch[2]; -} MP3SideInfo_t; - -#define SBLIMIT 32 -#define MAX_MP3_FRAME_SIZE 2500 /* also big enough for an 'ADU'ized frame */ - -class MP3FrameParams { -public: - MP3FrameParams(); - ~MP3FrameParams(); - - // 4-byte MPEG header: - unsigned hdr; - - // a buffer that can be used to hold the rest of the frame: - unsigned char frameBytes[MAX_MP3_FRAME_SIZE]; - - // public parameters derived from the header - void setParamsFromHeader(); // this sets them - Boolean isMPEG2; - unsigned layer; // currently only 3 is supported - unsigned bitrate; // in kbps - unsigned samplingFreq; - Boolean isStereo; - Boolean isFreeFormat; - unsigned frameSize; // doesn't include the initial 4-byte header - unsigned sideInfoSize; - Boolean hasCRC; - - void setBytePointer(unsigned char const* restOfFrame, - unsigned totNumBytes) {// called during setup - bv.setup((unsigned char*)restOfFrame, 0, 8*totNumBytes); - } - - // other, public parameters used when parsing input (perhaps get rid of) - unsigned oldHdr, firstHdr; - - // Extract (unpack) the side info from the frame into a struct: - void getSideInfo(MP3SideInfo& si); - - // The bit pointer used for reading data from frame data - unsigned getBits(unsigned numBits) { return bv.getBits(numBits); } - unsigned get1Bit() { return bv.get1Bit(); } - -private: - BitVector bv; - - // other, private parameters derived from the header - unsigned bitrateIndex; - unsigned samplingFreqIndex; - Boolean isMPEG2_5; - Boolean padding; - Boolean extension; - unsigned mode; - unsigned mode_ext; - Boolean copyright; - Boolean original; - unsigned emphasis; - unsigned stereo; - -private: - unsigned computeSideInfoSize(); -}; - -unsigned ComputeFrameSize(unsigned bitrate, unsigned samplingFreq, - Boolean usePadding, Boolean isMPEG2, - unsigned char layer); - -Boolean GetADUInfoFromMP3Frame(unsigned char const* framePtr, - unsigned totFrameSize, - unsigned& hdr, unsigned& frameSize, - MP3SideInfo& sideInfo, unsigned& sideInfoSize, - unsigned& backpointer, unsigned& aduSize); - -Boolean ZeroOutMP3SideInfo(unsigned char* framePtr, unsigned totFrameSize, - unsigned newBackpointer); - -unsigned TranscodeMP3ADU(unsigned char const* fromPtr, unsigned fromSize, - unsigned toBitrate, - unsigned char* toPtr, unsigned toMaxSize, - unsigned& availableBytesForBackpointer); - // returns the size of the resulting ADU (0 on failure) - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffman.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffman.cpp deleted file mode 100644 index 42f979c8398..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffman.cpp +++ /dev/null @@ -1,1039 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 internal implementation details (Huffman encoding) -// Implementation - -#include "MP3InternalsHuffman.hh" -#include -#include -#include - -MP3HuffmanEncodingInfo -::MP3HuffmanEncodingInfo(Boolean includeDecodedValues) { - if (includeDecodedValues) { - decodedValues = new unsigned[(SBLIMIT*SSLIMIT + 1)*4]; - } else { - decodedValues = NULL; - } -} - -MP3HuffmanEncodingInfo::~MP3HuffmanEncodingInfo() { - delete[] decodedValues; -} - -// This is crufty old code that needs to be cleaned up ##### - -static unsigned debugCount = 0; /* for debugging */ - -#define TRUNC_FAVORa - -void updateSideInfoForHuffman(MP3SideInfo& sideInfo, Boolean isMPEG2, - unsigned char const* mainDataPtr, - unsigned p23L0, unsigned p23L1, - unsigned& part23Length0a, - unsigned& part23Length0aTruncation, - unsigned& part23Length0b, - unsigned& part23Length0bTruncation, - unsigned& part23Length1a, - unsigned& part23Length1aTruncation, - unsigned& part23Length1b, - unsigned& part23Length1bTruncation) { - int i, j; - unsigned sfLength, origTotABsize, adjustment; - MP3SideInfo::gr_info_s_t* gr; - - /* First, Huffman-decode each part of the segment's main data, - to see at which bit-boundaries the samples appear: - */ - MP3HuffmanEncodingInfo hei; - - ++debugCount; -#ifdef DEBUG - fprintf(stderr, "usifh-start: p23L0: %d, p23L1: %d\n", p23L0, p23L1); -#endif - - /* Process granule 0 */ - { - gr = &(sideInfo.ch[0].gr[0]); - origTotABsize = gr->part2_3_length; - - MP3HuffmanDecode(gr, isMPEG2, mainDataPtr, 0, origTotABsize, sfLength, hei); - - /* Begin by computing new sizes for parts a & b (& their truncations) */ -#ifdef DEBUG - fprintf(stderr, "usifh-0: %d, %d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n", - hei.numSamples, - sfLength/8, sfLength%8, - hei.reg1Start/8, hei.reg1Start%8, - hei.reg2Start/8, hei.reg2Start%8, - hei.bigvalStart/8, hei.bigvalStart%8, - origTotABsize/8, origTotABsize%8); -#ifdef undef - { - unsigned k; - for (k = 0; k < hei.numSamples; ++k) { - fprintf(stderr, " %d:%d", - hei.allBitOffsets[k]/8, hei.allBitOffsets[k]%8); - } - fprintf(stderr, "\n"); - } -#endif -#endif - if (p23L0 < sfLength) { - /* We can't use this, so give it all to the next granule: */ - p23L1 += p23L0; - p23L0 = 0; - } - - part23Length0a = hei.bigvalStart; - part23Length0b = origTotABsize - hei.bigvalStart; - part23Length0aTruncation = part23Length0bTruncation = 0; - if (origTotABsize > p23L0) { - /* We need to shorten one or both of fields a & b */ - unsigned truncation = origTotABsize - p23L0; -#ifdef TRUNC_FAIRLY - part23Length0aTruncation = (truncation*(part23Length0a-sfLength)) - /(origTotABsize-sfLength); - part23Length0bTruncation = truncation - part23Length0aTruncation; -#endif -#ifdef TRUNC_FAVORa - part23Length0bTruncation - = (truncation > part23Length0b) ? part23Length0b : truncation; - part23Length0aTruncation = truncation - part23Length0bTruncation; -#endif -#ifdef TRUNC_FAVORb - part23Length0aTruncation = (truncation > part23Length0a-sfLength) - ? (part23Length0a-sfLength) : truncation; - part23Length0bTruncation = truncation - part23Length0aTruncation; -#endif - } - /* ASSERT: part23Length0xTruncation <= part23Length0x */ - part23Length0a -= part23Length0aTruncation; - part23Length0b -= part23Length0bTruncation; -#ifdef DEBUG - fprintf(stderr, "usifh-0: interim sizes: %d (%d), %d (%d)\n", - part23Length0a, part23Length0aTruncation, - part23Length0b, part23Length0bTruncation); -#endif - - /* Adjust these new lengths so they end on sample bit boundaries: */ - for (i = 0; i < (int)hei.numSamples; ++i) { - if (hei.allBitOffsets[i] == part23Length0a) break; - else if (hei.allBitOffsets[i] > part23Length0a) {--i; break;} - } - if (i < 0) { /* should happen only if we couldn't fit sfLength */ - i = 0; adjustment = 0; - } else { - adjustment = part23Length0a - hei.allBitOffsets[i]; - } -#ifdef DEBUG - fprintf(stderr, "%d usifh-0: adjustment 1: %d\n", debugCount, adjustment); -#endif - part23Length0a -= adjustment; - part23Length0aTruncation += adjustment; - /* Assign the bits we just shaved to field b and granule 1: */ - if (part23Length0bTruncation < adjustment) { - p23L1 += (adjustment - part23Length0bTruncation); - adjustment = part23Length0bTruncation; - } - part23Length0b += adjustment; - part23Length0bTruncation -= adjustment; - for (j = i; j < (int)hei.numSamples; ++j) { - if (hei.allBitOffsets[j] - == part23Length0a + part23Length0aTruncation + part23Length0b) - break; - else if (hei.allBitOffsets[j] - > part23Length0a + part23Length0aTruncation + part23Length0b) - {--j; break;} - } - if (j < 0) { /* should happen only if we couldn't fit sfLength */ - j = 0; adjustment = 0; - } else { - adjustment = part23Length0a+part23Length0aTruncation+part23Length0b - - hei.allBitOffsets[j]; - } -#ifdef DEBUG - fprintf(stderr, "%d usifh-0: adjustment 2: %d\n", debugCount, adjustment); -#endif - if (adjustment > part23Length0b) adjustment = part23Length0b; /*sanity*/ - part23Length0b -= adjustment; - part23Length0bTruncation += adjustment; - /* Assign the bits we just shaved to granule 1 */ - p23L1 += adjustment; - - if (part23Length0aTruncation > 0) { - /* Change the granule's 'big_values' field to reflect the truncation */ - gr->big_values = i; - } - } - - /* Process granule 1 (MPEG-1 only) */ - - if (isMPEG2) { - part23Length1a = part23Length1b = 0; - part23Length1aTruncation = part23Length1bTruncation = 0; - } else { - unsigned granule1Offset - = origTotABsize + sideInfo.ch[1].gr[0].part2_3_length; - - gr = &(sideInfo.ch[0].gr[1]); - origTotABsize = gr->part2_3_length; - - MP3HuffmanDecode(gr, isMPEG2, mainDataPtr, granule1Offset, - origTotABsize, sfLength, hei); - - /* Begin by computing new sizes for parts a & b (& their truncations) */ -#ifdef DEBUG - fprintf(stderr, "usifh-1: %d, %d:%d, %d:%d, %d:%d, %d:%d, %d:%d\n", - hei.numSamples, - sfLength/8, sfLength%8, - hei.reg1Start/8, hei.reg1Start%8, - hei.reg2Start/8, hei.reg2Start%8, - hei.bigvalStart/8, hei.bigvalStart%8, - origTotABsize/8, origTotABsize%8); -#ifdef undef - { - unsigned k; - for (k = 0; k < hei.numSamples; ++k) { - fprintf(stderr, " %d:%d", - hei.allBitOffsets[k]/8, hei.allBitOffsets[k]%8); - } - fprintf(stderr, "\n"); - } -#endif -#endif - if (p23L1 < sfLength) { - /* We can't use this, so give up on this granule: */ - p23L1 = 0; - } - - part23Length1a = hei.bigvalStart; - part23Length1b = origTotABsize - hei.bigvalStart; - part23Length1aTruncation = part23Length1bTruncation = 0; - if (origTotABsize > p23L1) { - /* We need to shorten one or both of fields a & b */ - unsigned truncation = origTotABsize - p23L1; -#ifdef TRUNC_FAIRLY - part23Length1aTruncation = (truncation*(part23Length1a-sfLength)) - /(origTotABsize-sfLength); - part23Length1bTruncation = truncation - part23Length1aTruncation; -#endif -#ifdef TRUNC_FAVORa - part23Length1bTruncation - = (truncation > part23Length1b) ? part23Length1b : truncation; - part23Length1aTruncation = truncation - part23Length1bTruncation; -#endif -#ifdef TRUNC_FAVORb - part23Length1aTruncation = (truncation > part23Length1a-sfLength) - ? (part23Length1a-sfLength) : truncation; - part23Length1bTruncation = truncation - part23Length1aTruncation; -#endif - } - /* ASSERT: part23Length1xTruncation <= part23Length1x */ - part23Length1a -= part23Length1aTruncation; - part23Length1b -= part23Length1bTruncation; -#ifdef DEBUG - fprintf(stderr, "usifh-1: interim sizes: %d (%d), %d (%d)\n", - part23Length1a, part23Length1aTruncation, - part23Length1b, part23Length1bTruncation); -#endif - - /* Adjust these new lengths so they end on sample bit boundaries: */ - for (i = 0; i < (int)hei.numSamples; ++i) { - if (hei.allBitOffsets[i] == part23Length1a) break; - else if (hei.allBitOffsets[i] > part23Length1a) {--i; break;} - } - if (i < 0) { /* should happen only if we couldn't fit sfLength */ - i = 0; adjustment = 0; - } else { - adjustment = part23Length1a - hei.allBitOffsets[i]; - } -#ifdef DEBUG - fprintf(stderr, "%d usifh-1: adjustment 0: %d\n", debugCount, adjustment); -#endif - part23Length1a -= adjustment; - part23Length1aTruncation += adjustment; - /* Assign the bits we just shaved to field b: */ - if (part23Length1bTruncation < adjustment) { - adjustment = part23Length1bTruncation; - } - part23Length1b += adjustment; - part23Length1bTruncation -= adjustment; - for (j = i; j < (int)hei.numSamples; ++j) { - if (hei.allBitOffsets[j] - == part23Length1a + part23Length1aTruncation + part23Length1b) - break; - else if (hei.allBitOffsets[j] - > part23Length1a + part23Length1aTruncation + part23Length1b) - {--j; break;} - } - if (j < 0) { /* should happen only if we couldn't fit sfLength */ - j = 0; adjustment = 0; - } else { - adjustment = part23Length1a+part23Length1aTruncation+part23Length1b - - hei.allBitOffsets[j]; - } -#ifdef DEBUG - fprintf(stderr, "%d usifh-1: adjustment 1: %d\n", debugCount, adjustment); -#endif - if (adjustment > part23Length1b) adjustment = part23Length1b; /*sanity*/ - part23Length1b -= adjustment; - part23Length1bTruncation += adjustment; - - if (part23Length1aTruncation > 0) { - /* Change the granule's 'big_values' field to reflect the truncation */ - gr->big_values = i; - } - } -#ifdef DEBUG - fprintf(stderr, "usifh-end, new vals: %d (%d), %d (%d), %d (%d), %d (%d)\n", - part23Length0a, part23Length0aTruncation, - part23Length0b, part23Length0bTruncation, - part23Length1a, part23Length1aTruncation, - part23Length1b, part23Length1bTruncation); -#endif -} - -static void rsf_getline(char* line, unsigned max, unsigned char**fi) { - unsigned i; - for (i = 0; i < max; ++i) { - line[i] = *(*fi)++; - if (line[i] == '\n') { - line[i++] = '\0'; - return; - } - } - line[i] = '\0'; -} - -static void rsfscanf(unsigned char **fi, unsigned int* v) { - while (sscanf((char*)*fi, "%x", v) == 0) { - /* skip past the next '\0' */ - while (*(*fi)++ != '\0') {} - } - - /* skip past any white-space before the value: */ - while (*(*fi) <= ' ') ++(*fi); - - /* skip past the value: */ - while (*(*fi) > ' ') ++(*fi); -} - -#define HUFFBITS unsigned long int -#define SIZEOF_HUFFBITS 4 -#define HTN 34 -#define MXOFF 250 - -struct huffcodetab { - char tablename[3]; /*string, containing table_description */ - unsigned int xlen; /*max. x-index+ */ - unsigned int ylen; /*max. y-index+ */ - unsigned int linbits; /*number of linbits */ - unsigned int linmax; /*max number to be stored in linbits */ - int ref; /*a positive value indicates a reference*/ - HUFFBITS *table; /*pointer to array[xlen][ylen] */ - unsigned char *hlen; /*pointer to array[xlen][ylen] */ - unsigned char(*val)[2];/*decoder tree */ - unsigned int treelen; /*length of decoder tree */ -}; - -static struct huffcodetab rsf_ht[HTN]; // array of all huffcodetable headers - /* 0..31 Huffman code table 0..31 */ - /* 32,33 count1-tables */ - -/* read the huffman decoder table */ -static int read_decoder_table(unsigned char* fi) { - int n,i,nn,t; - unsigned int v0,v1; - char command[100],line[100]; - for (n=0;nscalefac_compress]; - int num1 = slen[1][gr_info->scalefac_compress]; - - if (gr_info->block_type == 2) - { - numbits = (num0 + num1) * 18; - - if (gr_info->mixed_block_flag) { - numbits -= num0; /* num0 * 17 + num1 * 18 */ - } - } - else - { - int scfsi = gr_info->scfsi; - - if(scfsi < 0) { /* scfsi < 0 => granule == 0 */ - numbits = (num0 + num1) * 10 + num0; - } - else { - numbits = 0; - if(!(scfsi & 0x8)) { - numbits += num0 * 6; - } - else { - } - - if(!(scfsi & 0x4)) { - numbits += num0 * 5; - } - else { - } - - if(!(scfsi & 0x2)) { - numbits += num1 * 5; - } - else { - } - - if(!(scfsi & 0x1)) { - numbits += num1 * 5; - } - else { - } - } - } - - return numbits; -} - -extern unsigned n_slen2[]; -extern unsigned i_slen2[]; - -static unsigned rsf_get_scale_factors_2(MP3SideInfo::gr_info_s_t *gr_info) { - unsigned char const* pnt; - int i; - unsigned int slen; - int n = 0; - int numbits = 0; - -#ifdef undef - if(i_stereo) /* i_stereo AND second channel -> do_layer3() checks this */ - slen = i_slen2[gr_info->scalefac_compress>>1]; - else -#endif - slen = n_slen2[gr_info->scalefac_compress]; - - gr_info->preflag = (slen>>15) & 0x1; - - n = 0; - if( gr_info->block_type == 2 ) { - n++; - if(gr_info->mixed_block_flag) - n++; - } - - pnt = stab[n][(slen>>12)&0x7]; - - for(i=0;i<4;i++) { - int num = slen & 0x7; - slen >>= 3; - numbits += pnt[i] * num; - } - - return numbits; -} - -static unsigned getScaleFactorsLength(MP3SideInfo::gr_info_s_t* gr, - Boolean isMPEG2) { - return isMPEG2 ? rsf_get_scale_factors_2(gr) - : rsf_get_scale_factors_1(gr); -} - -static int rsf_huffman_decoder(BitVector& bv, - struct huffcodetab const* h, - int* x, int* y, int* v, int* w); // forward - -void MP3HuffmanDecode(MP3SideInfo::gr_info_s_t* gr, int isMPEG2, - unsigned char const* fromBasePtr, - unsigned fromBitOffset, unsigned fromLength, - unsigned& scaleFactorsLength, - MP3HuffmanEncodingInfo& hei) { - unsigned i; - int x, y, v, w; - struct huffcodetab *h; - BitVector bv((unsigned char*)fromBasePtr, fromBitOffset, fromLength); - - /* Compute the size of the scale factors (& also advance bv): */ - scaleFactorsLength = getScaleFactorsLength(gr, isMPEG2); - bv.skipBits(scaleFactorsLength); - - initialize_huffman(); - - hei.reg1Start = hei.reg2Start = hei.numSamples = 0; - - /* Read bigvalues area. */ - if (gr->big_values < gr->region1start + gr->region2start) { - gr->big_values = gr->region1start + gr->region2start; /* sanity check */ - } - for (i = 0; i < gr->big_values; ++i) { - if (i < gr->region1start) { - /* in region 0 */ - h = &rsf_ht[gr->table_select[0]]; - } else if (i < gr->region2start) { - /* in region 1 */ - h = &rsf_ht[gr->table_select[1]]; - if (hei.reg1Start == 0) { - hei.reg1Start = bv.curBitIndex(); - } - } else { - /* in region 2 */ - h = &rsf_ht[gr->table_select[2]]; - if (hei.reg2Start == 0) { - hei.reg2Start = bv.curBitIndex(); - } - } - - hei.allBitOffsets[i] = bv.curBitIndex(); - rsf_huffman_decoder(bv, h, &x, &y, &v, &w); - if (hei.decodedValues != NULL) { - // Record the decoded values: - unsigned* ptr = &hei.decodedValues[4*i]; - ptr[0] = x; ptr[1] = y; ptr[2] = v; ptr[3] = w; - } - } - hei.bigvalStart = bv.curBitIndex(); - - /* Read count1 area. */ - h = &rsf_ht[gr->count1table_select+32]; - while (bv.curBitIndex() < bv.totNumBits() && i < SSLIMIT*SBLIMIT) { - hei.allBitOffsets[i] = bv.curBitIndex(); - rsf_huffman_decoder(bv, h, &x, &y, &v, &w); - if (hei.decodedValues != NULL) { - // Record the decoded values: - unsigned* ptr = &hei.decodedValues[4*i]; - ptr[0] = x; ptr[1] = y; ptr[2] = v; ptr[3] = w; - } - ++i; - } - - hei.allBitOffsets[i] = bv.curBitIndex(); - hei.numSamples = i; -} - -HUFFBITS dmask = 1 << (SIZEOF_HUFFBITS*8-1); -unsigned int hs = SIZEOF_HUFFBITS*8; - -/* do the huffman-decoding */ -static int rsf_huffman_decoder(BitVector& bv, - struct huffcodetab const* h, // ptr to huffman code record - /* unsigned */ int *x, // returns decoded x value - /* unsigned */ int *y, // returns decoded y value - int* v, int* w) { - HUFFBITS level; - unsigned point = 0; - int error = 1; - level = dmask; - *x = *y = *v = *w = 0; - if (h->val == NULL) return 2; - - /* table 0 needs no bits */ - if (h->treelen == 0) return 0; - - /* Lookup in Huffman table. */ - - do { - if (h->val[point][0]==0) { /*end of tree*/ - *x = h->val[point][1] >> 4; - *y = h->val[point][1] & 0xf; - - error = 0; - break; - } - if (bv.get1Bit()) { - while (h->val[point][1] >= MXOFF) point += h->val[point][1]; - point += h->val[point][1]; - } - else { - while (h->val[point][0] >= MXOFF) point += h->val[point][0]; - point += h->val[point][0]; - } - level >>= 1; - } while (level || (point < h->treelen) ); -///// } while (level || (point < rsf_ht->treelen) ); - - /* Check for error. */ - - if (error) { /* set x and y to a medium value as a simple concealment */ - printf("Illegal Huffman code in data.\n"); - *x = ((h->xlen-1) << 1); - *y = ((h->ylen-1) << 1); - } - - /* Process sign encodings for quadruples tables. */ - - if (h->tablename[0] == '3' - && (h->tablename[1] == '2' || h->tablename[1] == '3')) { - *v = (*y>>3) & 1; - *w = (*y>>2) & 1; - *x = (*y>>1) & 1; - *y = *y & 1; - - if (*v) - if (bv.get1Bit() == 1) *v = -*v; - if (*w) - if (bv.get1Bit() == 1) *w = -*w; - if (*x) - if (bv.get1Bit() == 1) *x = -*x; - if (*y) - if (bv.get1Bit() == 1) *y = -*y; - } - - /* Process sign and escape encodings for dual tables. */ - - else { - if (h->linbits) - if ((h->xlen-1) == (unsigned)*x) - *x += bv.getBits(h->linbits); - if (*x) - if (bv.get1Bit() == 1) *x = -*x; - if (h->linbits) - if ((h->ylen-1) == (unsigned)*y) - *y += bv.getBits(h->linbits); - if (*y) - if (bv.get1Bit() == 1) *y = -*y; - } - - return error; -} - -#ifdef DO_HUFFMAN_ENCODING -inline int getNextSample(unsigned char const*& fromPtr) { - int sample -#ifdef FOUR_BYTE_SAMPLES - = (fromPtr[0]<<24) | (fromPtr[1]<<16) | (fromPtr[2]<<8) | fromPtr[3]; -#else -#ifdef TWO_BYTE_SAMPLES - = (fromPtr[0]<<8) | fromPtr[1]; -#else - // ONE_BYTE_SAMPLES - = fromPtr[0]; -#endif -#endif - fromPtr += BYTES_PER_SAMPLE_VALUE; - return sample; -} - -static void rsf_huffman_encoder(BitVector& bv, - struct huffcodetab* h, - int x, int y, int v, int w); // forward - -unsigned MP3HuffmanEncode(MP3SideInfo::gr_info_s_t const* gr, - unsigned char const* fromPtr, - unsigned char* toPtr, unsigned toBitOffset, - unsigned numHuffBits) { - unsigned i; - struct huffcodetab *h; - int x, y, v, w; - BitVector bv(toPtr, toBitOffset, numHuffBits); - - initialize_huffman(); - - // Encode big_values area: - unsigned big_values = gr->big_values; - if (big_values < gr->region1start + gr->region2start) { - big_values = gr->region1start + gr->region2start; /* sanity check */ - } - for (i = 0; i < big_values; ++i) { - if (i < gr->region1start) { - /* in region 0 */ - h = &rsf_ht[gr->table_select[0]]; - } else if (i < gr->region2start) { - /* in region 1 */ - h = &rsf_ht[gr->table_select[1]]; - } else { - /* in region 2 */ - h = &rsf_ht[gr->table_select[2]]; - } - - x = getNextSample(fromPtr); - y = getNextSample(fromPtr); - v = getNextSample(fromPtr); - w = getNextSample(fromPtr); - rsf_huffman_encoder(bv, h, x, y, v, w); - } - - // Encode count1 area: - h = &rsf_ht[gr->count1table_select+32]; - while (bv.curBitIndex() < bv.totNumBits() && i < SSLIMIT*SBLIMIT) { - x = getNextSample(fromPtr); - y = getNextSample(fromPtr); - v = getNextSample(fromPtr); - w = getNextSample(fromPtr); - rsf_huffman_encoder(bv, h, x, y, v, w); - ++i; - } - - return i; -} - -static Boolean lookupHuffmanTableEntry(struct huffcodetab const* h, - HUFFBITS bits, unsigned bitsLength, - unsigned char& xy) { - unsigned point = 0; - unsigned mask = 1; - unsigned numBitsTestedSoFar = 0; - do { - if (h->val[point][0]==0) { // end of tree - xy = h->val[point][1]; - if (h->hlen[xy] == 0) { // this entry hasn't already been used - h->table[xy] = bits; - h->hlen[xy] = bitsLength; - return True; - } else { // this entry has already been seen - return False; - } - } - - if (numBitsTestedSoFar++ == bitsLength) { - // We don't yet have enough bits for this prefix - return False; - } - if (bits&mask) { - while (h->val[point][1] >= MXOFF) point += h->val[point][1]; - point += h->val[point][1]; - } else { - while (h->val[point][0] >= MXOFF) point += h->val[point][0]; - point += h->val[point][0]; - } - mask <<= 1; - } while (mask || (point < h->treelen)); - - return False; -} - -static void buildHuffmanEncodingTable(struct huffcodetab* h) { - h->table = new unsigned long[256]; - h->hlen = new unsigned char[256]; - if (h->table == NULL || h->hlen == NULL) { h->table = NULL; return; } - for (unsigned i = 0; i < 256; ++i) { - h->table[i] = 0; h->hlen[i] = 0; - } - - // Look up entries for each possible bit sequence length: - unsigned maxNumEntries = h->xlen * h->ylen; - unsigned numEntries = 0; - unsigned powerOf2 = 1; - for (unsigned bitsLength = 1; - bitsLength <= 8*SIZEOF_HUFFBITS; ++bitsLength) { - powerOf2 *= 2; - for (HUFFBITS bits = 0; bits < powerOf2; ++bits) { - // Find the table value - if any - for 'bits' (length 'bitsLength'): - unsigned char xy; - if (lookupHuffmanTableEntry(h, bits, bitsLength, xy)) { - ++numEntries; - if (numEntries == maxNumEntries) return; // we're done - } - } - } -#ifdef DEBUG - fprintf(stderr, "Didn't find enough entries!\n"); // shouldn't happen -#endif -} - -static void lookupXYandPutBits(BitVector& bv, struct huffcodetab const* h, - unsigned char xy) { - HUFFBITS bits = h->table[xy]; - unsigned bitsLength = h->hlen[xy]; - - // Note that "bits" is in reverse order, so read them from right-to-left: - while (bitsLength-- > 0) { - bv.put1Bit(bits&0x00000001); - bits >>= 1; - } -} - -static void putLinbits(BitVector& bv, struct huffcodetab const* h, - HUFFBITS bits) { - bv.putBits(bits, h->linbits); -} - -static void rsf_huffman_encoder(BitVector& bv, - struct huffcodetab* h, - int x, int y, int v, int w) { - if (h->val == NULL) return; - - /* table 0 produces no bits */ - if (h->treelen == 0) return; - - if (h->table == NULL) { - // We haven't yet built the encoding array for this table; do it now: - buildHuffmanEncodingTable(h); - if (h->table == NULL) return; - } - - Boolean xIsNeg = False, yIsNeg = False, vIsNeg = False, wIsNeg = False; - unsigned char xy; - -#ifdef FOUR_BYTE_SAMPLES -#else -#ifdef TWO_BYTE_SAMPLES - // Convert 2-byte negative numbers to their 4-byte equivalents: - if (x&0x8000) x |= 0xFFFF0000; - if (y&0x8000) y |= 0xFFFF0000; - if (v&0x8000) v |= 0xFFFF0000; - if (w&0x8000) w |= 0xFFFF0000; -#else - // ONE_BYTE_SAMPLES - // Convert 1-byte negative numbers to their 4-byte equivalents: - if (x&0x80) x |= 0xFFFFFF00; - if (y&0x80) y |= 0xFFFFFF00; - if (v&0x80) v |= 0xFFFFFF00; - if (w&0x80) w |= 0xFFFFFF00; -#endif -#endif - - if (h->tablename[0] == '3' - && (h->tablename[1] == '2' || h->tablename[1] == '3')) {// quad tables - if (x < 0) { xIsNeg = True; x = -x; } - if (y < 0) { yIsNeg = True; y = -y; } - if (v < 0) { vIsNeg = True; v = -v; } - if (w < 0) { wIsNeg = True; w = -w; } - - // Sanity check: x,y,v,w must all be 0 or 1: - if (x>1 || y>1 || v>1 || w>1) { -#ifdef DEBUG - fprintf(stderr, "rsf_huffman_encoder quad sanity check fails: %x,%x,%x,%x\n", x, y, v, w); -#endif - } - - xy = (v<<3)|(w<<2)|(x<<1)|y; - lookupXYandPutBits(bv, h, xy); - - if (v) bv.put1Bit(vIsNeg); - if (w) bv.put1Bit(wIsNeg); - if (x) bv.put1Bit(xIsNeg); - if (y) bv.put1Bit(yIsNeg); - } else { // dual tables - // Sanity check: v and w must be 0: - if (v != 0 || w != 0) { -#ifdef DEBUG - fprintf(stderr, "rsf_huffman_encoder dual sanity check 1 fails: %x,%x,%x,%x\n", x, y, v, w); -#endif - } - - if (x < 0) { xIsNeg = True; x = -x; } - if (y < 0) { yIsNeg = True; y = -y; } - - // Sanity check: x and y must be <= 255: - if (x > 255 || y > 255) { -#ifdef DEBUG - fprintf(stderr, "rsf_huffman_encoder dual sanity check 2 fails: %x,%x,%x,%x\n", x, y, v, w); -#endif - } - - int xl1 = h->xlen-1; - int yl1 = h->ylen-1; - unsigned linbitsX = 0; unsigned linbitsY = 0; - - if (((x < xl1) || (xl1 == 0)) && (y < yl1)) { - // normal case - xy = (x<<4)|y; - lookupXYandPutBits(bv, h, xy); - if (x) bv.put1Bit(xIsNeg); - if (y) bv.put1Bit(yIsNeg); - } else if (x >= xl1) { - linbitsX = (unsigned)(x - xl1); - if (linbitsX > h->linmax) { -#ifdef DEBUG - fprintf(stderr,"warning: Huffman X table overflow\n"); -#endif - linbitsX = h->linmax; - }; - - if (y >= yl1) { - xy = (xl1<<4)|yl1; - lookupXYandPutBits(bv, h, xy); - linbitsY = (unsigned)(y - yl1); - if (linbitsY > h->linmax) { -#ifdef DEBUG - fprintf(stderr,"warning: Huffman Y table overflow\n"); -#endif - linbitsY = h->linmax; - }; - - if (h->linbits) putLinbits(bv, h, linbitsX); - if (x) bv.put1Bit(xIsNeg); - if (h->linbits) putLinbits(bv, h, linbitsY); - if (y) bv.put1Bit(yIsNeg); - } else { /* x >= h->xlen, y < h->ylen */ - xy = (xl1<<4)|y; - lookupXYandPutBits(bv, h, xy); - if (h->linbits) putLinbits(bv, h, linbitsX); - if (x) bv.put1Bit(xIsNeg); - if (y) bv.put1Bit(yIsNeg); - } - } else { /* ((x < h->xlen) && (y >= h->ylen)) */ - xy = (x<<4)|yl1; - lookupXYandPutBits(bv, h, xy); - linbitsY = y-yl1; - if (linbitsY > h->linmax) { -#ifdef DEBUG - fprintf(stderr,"warning: Huffman Y table overflow\n"); -#endif - linbitsY = h->linmax; - }; - if (x) bv.put1Bit(xIsNeg); - if (h->linbits) putLinbits(bv, h, linbitsY); - if (y) bv.put1Bit(yIsNeg); - } - } -} -#endif - -#ifdef undef -/* The system uses a variety of data files. By opening them via this - function, we can accommodate various locations. */ - -FILE *OpenTableFile(name) -char *name; -{ -char fulname[80]; -FILE *f; - - fulname[0] = '\0'; - - strcat(fulname, name); - if( (f=fopen(fulname,"r"))==NULL ) { - fprintf(stderr,"OpenTable: could not find %s\n", fulname); - } - -/* The following was used to generate an internal version of the file #####*/ - { -FILE *testfd = fopen("rsf_hufftab.c", "w"); -unsigned char buf[100]; -unsigned i; -for (i = 0; i < 100; ++i) buf[i] = '\0'; -while (fgets(buf, 100, f) != NULL) { - unsigned j; - for (j = 0; buf[j] != '\0'; ++j) { - fprintf(testfd, "0x%02x, ", buf[j]); - } - for (i = 0; i < 100; ++i) buf[i] = '\0'; -} -fclose(testfd); -exit(0); - } -/*#####*/ - return f; -} -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffman.hh b/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffman.hh deleted file mode 100644 index 6ef5efb6b35..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffman.hh +++ /dev/null @@ -1,82 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 internal implementation details (Huffman encoding) -// C++ header - -#ifndef _MP3_INTERNALS_HUFFMAN_HH -#define _MP3_INTERNALS_HUFFMAN_HH - -#ifndef _MP3_INTERNALS_HH -#include "MP3Internals.hh" -#endif - -void updateSideInfoForHuffman(MP3SideInfo& sideInfo, Boolean isMPEG2, - unsigned char const* mainDataPtr, - unsigned p23L0, unsigned p23L1, - unsigned& part23Length0a, - unsigned& part23Length0aTruncation, - unsigned& part23Length0b, - unsigned& part23Length0bTruncation, - unsigned& part23Length1a, - unsigned& part23Length1aTruncation, - unsigned& part23Length1b, - unsigned& part23Length1bTruncation); - -#define SSLIMIT 18 - -class MP3HuffmanEncodingInfo { -public: - MP3HuffmanEncodingInfo(Boolean includeDecodedValues = False); - ~MP3HuffmanEncodingInfo(); - -public: - unsigned numSamples; - unsigned allBitOffsets[SBLIMIT*SSLIMIT + 1]; - unsigned reg1Start, reg2Start, bigvalStart; /* special bit offsets */ - unsigned* decodedValues; -}; - -/* forward */ -void MP3HuffmanDecode(MP3SideInfo::gr_info_s_t* gr, int isMPEG2, - unsigned char const* fromBasePtr, - unsigned fromBitOffset, unsigned fromLength, - unsigned& scaleFactorsLength, - MP3HuffmanEncodingInfo& hei); - -extern unsigned char huffdec[]; // huffman table data - -// The following are used if we process Huffman-decoded values -#ifdef FOUR_BYTE_SAMPLES -#define BYTES_PER_SAMPLE_VALUE 4 -#else -#ifdef TWO_BYTE_SAMPLES -#define BYTES_PER_SAMPLE_VALUE 2 -#else -// ONE_BYTE_SAMPLES -#define BYTES_PER_SAMPLE_VALUE 1 -#endif -#endif - -#ifdef DO_HUFFMAN_ENCODING -unsigned MP3HuffmanEncode(MP3SideInfo::gr_info_s_t const* gr, - unsigned char const* fromPtr, - unsigned char* toPtr, unsigned toBitOffset, - unsigned numHuffBits); -#endif - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffmanTable.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffmanTable.cpp deleted file mode 100644 index b630c1de7df..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3InternalsHuffmanTable.cpp +++ /dev/null @@ -1,1548 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 internal implementation details (Huffman encoding) -// Table - -#include "MP3InternalsHuffman.hh" - -unsigned char huffdec[] = { -0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x30, 0x20, 0x20, -0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x0a, -0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x0a, 0x2e, -0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x20, 0x37, -0x20, 0x20, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x30, 0x0a, 0x2e, 0x74, -0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, -0x31, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x37, 0x20, 0x20, 0x33, 0x20, 0x20, 0x33, 0x20, -0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, -0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, 0x20, 0x30, 0x20, 0x32, 0x31, -0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, -0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, -0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x32, 0x20, 0x0a, 0x0a, 0x2e, 0x74, -0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x33, 0x20, 0x20, 0x31, 0x37, 0x20, -0x20, 0x33, 0x20, 0x20, 0x33, 0x20, 0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, -0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, -0x20, 0x20, 0x30, 0x20, 0x32, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, -0x32, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, -0x34, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, -0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, -0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x35, 0x20, -0x20, 0x33, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x34, 0x20, 0x20, 0x30, -0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, -0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, 0x0a, -0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x32, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x32, 0x20, -0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x32, 0x20, -0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x20, 0x33, 0x20, 0x20, 0x30, 0x20, 0x31, 0x33, 0x20, -0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x32, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x33, -0x20, 0x20, 0x30, 0x20, 0x33, 0x33, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, -0x62, 0x6c, 0x65, 0x20, 0x20, 0x36, 0x20, 0x20, 0x33, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x34, 0x20, 0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, -0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x31, 0x30, 0x20, -0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, -0x20, 0x30, 0x20, 0x32, 0x31, 0x20, 0x0a, 0x20, 0x36, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x32, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, -0x20, 0x20, 0x30, 0x20, 0x32, 0x32, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x33, -0x30, 0x20, 0x20, 0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, -0x33, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, -0x37, 0x20, 0x20, 0x37, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x36, 0x20, -0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, -0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, -0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, -0x31, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, -0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x32, 0x20, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, -0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x31, 0x33, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x33, 0x20, 0x20, 0x30, 0x20, -0x20, 0x34, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x34, 0x30, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x34, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x32, 0x20, 0x20, 0x30, -0x20, 0x32, 0x34, 0x20, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x33, 0x20, 0x20, 0x30, -0x20, 0x34, 0x33, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x35, 0x30, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x33, 0x34, 0x20, 0x20, 0x30, 0x20, 0x20, 0x35, 0x20, 0x20, -0x30, 0x20, 0x35, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x35, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x32, 0x20, 0x20, -0x30, 0x20, 0x32, 0x35, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x34, 0x20, -0x20, 0x30, 0x20, 0x33, 0x35, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x33, 0x20, -0x20, 0x30, 0x20, 0x35, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x34, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, 0x20, -0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x38, 0x20, -0x20, 0x37, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x36, 0x20, 0x20, 0x30, -0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x32, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x32, 0x20, 0x0a, -0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, -0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x32, 0x32, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, -0x20, 0x30, 0x20, 0x20, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x30, 0x20, 0x33, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x33, -0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x33, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x34, 0x20, 0x20, 0x30, 0x20, 0x34, -0x32, 0x20, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, -0x33, 0x20, 0x20, 0x30, 0x20, 0x35, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x34, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x34, 0x20, 0x20, 0x30, 0x20, -0x35, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x35, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x35, 0x20, 0x20, 0x30, 0x20, -0x35, 0x32, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x32, 0x35, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x34, 0x20, 0x20, 0x30, -0x20, 0x33, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x35, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x34, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x35, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, 0x20, 0x0a, 0x0a, -0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x20, 0x39, 0x20, 0x20, 0x37, -0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x36, 0x20, 0x20, 0x30, 0x0a, 0x2e, -0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x38, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, -0x31, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, 0x61, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, 0x0a, 0x20, 0x30, -0x20, 0x32, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x31, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x32, 0x20, 0x20, 0x63, -0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x33, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x33, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x33, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x33, 0x20, 0x20, -0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x34, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x30, 0x20, -0x20, 0x30, 0x20, 0x33, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x34, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x34, 0x20, -0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x30, 0x20, -0x0a, 0x20, 0x30, 0x20, 0x34, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x33, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x31, -0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x35, -0x20, 0x20, 0x30, 0x20, 0x35, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x35, 0x20, 0x20, 0x30, 0x20, 0x34, 0x34, -0x20, 0x0a, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, -0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, -0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, -0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, -0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, 0x20, 0x0a, 0x0a, 0x2e, 0x74, -0x61, 0x62, 0x6c, 0x65, 0x20, 0x31, 0x30, 0x20, 0x31, 0x32, 0x37, 0x20, -0x20, 0x38, 0x20, 0x20, 0x38, 0x20, 0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, -0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x20, -0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x32, 0x20, 0x31, 0x63, 0x20, 0x20, -0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x32, 0x20, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, -0x31, 0x33, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x33, 0x20, 0x20, 0x30, 0x20, -0x34, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x31, 0x20, 0x0a, 0x20, 0x30, -0x20, 0x31, 0x34, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x30, -0x20, 0x33, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x34, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x34, 0x20, 0x31, 0x63, -0x20, 0x20, 0x31, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x30, 0x20, 0x20, -0x30, 0x20, 0x20, 0x35, 0x20, 0x20, 0x30, 0x20, 0x36, 0x30, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x36, 0x20, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x33, 0x20, 0x0a, -0x20, 0x30, 0x20, 0x33, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x35, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x32, 0x20, -0x20, 0x30, 0x20, 0x32, 0x35, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x36, 0x20, -0x20, 0x30, 0x20, 0x33, 0x36, 0x20, 0x20, 0x30, 0x20, 0x37, 0x31, 0x20, -0x0a, 0x31, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x37, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x34, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x33, -0x20, 0x20, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x33, 0x35, 0x20, 0x20, 0x30, 0x20, 0x34, -0x35, 0x20, 0x20, 0x30, 0x20, 0x36, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x37, 0x20, 0x20, 0x30, 0x20, 0x36, -0x34, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, -0x32, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x32, 0x37, 0x20, 0x20, 0x36, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x36, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x35, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x36, 0x20, 0x20, 0x30, 0x20, -0x37, 0x33, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x33, 0x37, 0x20, 0x20, 0x30, 0x20, 0x36, 0x35, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x36, 0x20, 0x20, 0x30, -0x20, 0x37, 0x34, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x37, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x36, 0x20, 0x20, 0x30, -0x20, 0x37, 0x35, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x37, 0x20, 0x20, -0x30, 0x20, 0x37, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x36, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, 0x37, 0x20, 0x0a, -0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x31, 0x31, 0x20, 0x31, -0x32, 0x37, 0x20, 0x20, 0x38, 0x20, 0x20, 0x38, 0x20, 0x20, 0x30, 0x0a, -0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x31, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x31, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x30, 0x20, 0x31, 0x32, 0x20, 0x31, -0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x32, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x20, -0x30, 0x20, 0x20, 0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x31, 0x20, -0x20, 0x30, 0x20, 0x31, 0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x32, 0x20, -0x20, 0x30, 0x20, 0x32, 0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x30, 0x20, -0x20, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x30, 0x20, 0x34, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x34, -0x20, 0x31, 0x65, 0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, -0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x32, -0x20, 0x20, 0x30, 0x20, 0x32, 0x34, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x33, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x33, 0x20, 0x20, 0x30, 0x20, 0x35, -0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, -0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, -0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, -0x36, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x32, 0x36, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x32, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x35, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x35, 0x20, 0x20, 0x30, 0x20, -0x35, 0x32, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x61, 0x20, -0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x32, 0x35, 0x20, 0x20, 0x30, 0x20, 0x34, 0x34, 0x20, 0x20, 0x30, -0x20, 0x36, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x36, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x36, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x37, 0x30, 0x20, 0x20, 0x30, 0x20, 0x31, 0x37, 0x20, 0x20, 0x30, -0x20, 0x37, 0x31, 0x20, 0x0a, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x37, 0x20, 0x20, -0x30, 0x20, 0x36, 0x34, 0x20, 0x20, 0x30, 0x20, 0x37, 0x32, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x37, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x35, 0x33, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x33, 0x35, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x34, 0x20, -0x20, 0x30, 0x20, 0x34, 0x35, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x34, 0x36, 0x20, 0x20, 0x30, 0x20, 0x37, 0x33, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x37, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x36, 0x35, -0x20, 0x20, 0x30, 0x20, 0x35, 0x36, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, -0x20, 0x20, 0x30, 0x20, 0x35, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, 0x34, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x37, -0x20, 0x20, 0x30, 0x20, 0x36, 0x36, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, -0x35, 0x20, 0x20, 0x30, 0x20, 0x37, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, -0x37, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x31, -0x32, 0x20, 0x31, 0x32, 0x37, 0x20, 0x20, 0x38, 0x20, 0x20, 0x38, 0x20, -0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, -0x0a, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, -0x20, 0x0a, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x32, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x32, 0x20, 0x20, 0x30, 0x20, 0x33, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x33, 0x20, 0x20, 0x30, 0x20, -0x34, 0x30, 0x20, 0x31, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x30, 0x20, -0x32, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x34, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x33, 0x33, 0x20, 0x20, 0x61, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x34, 0x20, 0x20, 0x30, -0x20, 0x34, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x32, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x30, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x34, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x34, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x35, 0x20, 0x31, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, -0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x35, 0x32, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x32, 0x35, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x33, 0x20, -0x20, 0x30, 0x20, 0x33, 0x35, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x30, 0x20, -0x20, 0x30, 0x20, 0x31, 0x36, 0x20, 0x20, 0x30, 0x20, 0x36, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x36, 0x32, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x32, 0x36, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x35, -0x20, 0x20, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x30, 0x20, 0x34, 0x34, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x34, -0x20, 0x20, 0x30, 0x20, 0x34, 0x35, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, -0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x36, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, -0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x37, 0x20, 0x0a, 0x20, 0x30, 0x20, -0x36, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x34, 0x36, 0x20, 0x20, 0x30, 0x20, 0x37, 0x32, 0x20, 0x20, 0x61, 0x20, -0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x37, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, 0x20, 0x20, 0x30, 0x20, -0x37, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, -0x20, 0x33, 0x37, 0x20, 0x20, 0x30, 0x20, 0x35, 0x36, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x35, 0x20, 0x20, 0x30, -0x20, 0x37, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x34, 0x37, 0x20, 0x20, 0x30, 0x20, 0x36, 0x36, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x37, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x37, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x36, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x37, 0x20, 0x20, -0x30, 0x20, 0x37, 0x37, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, -0x65, 0x20, 0x31, 0x33, 0x20, 0x35, 0x31, 0x31, 0x20, 0x31, 0x36, 0x20, -0x31, 0x36, 0x20, 0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, -0x61, 0x74, 0x61, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x30, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x31, 0x31, 0x20, 0x31, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, 0x20, -0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x32, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x32, 0x20, 0x20, -0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x32, 0x20, 0x20, -0x30, 0x20, 0x33, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x20, 0x33, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x33, 0x31, 0x20, -0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x31, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x33, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x34, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x34, 0x20, -0x20, 0x30, 0x20, 0x34, 0x31, 0x20, 0x0a, 0x34, 0x36, 0x20, 0x20, 0x31, -0x20, 0x31, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x33, 0x33, 0x20, 0x20, 0x30, 0x20, 0x34, 0x32, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x34, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x35, -0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, -0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x34, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x35, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, -0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x32, 0x20, 0x0a, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x35, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x34, 0x20, 0x20, 0x30, 0x20, -0x35, 0x33, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x30, 0x20, 0x20, 0x30, 0x20, -0x20, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, -0x20, 0x36, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x36, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x38, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x38, 0x20, 0x20, 0x30, -0x20, 0x38, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x35, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x36, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x32, 0x36, 0x20, 0x20, 0x30, 0x20, 0x35, 0x34, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x34, 0x35, 0x20, 0x20, 0x30, 0x20, 0x36, 0x33, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x36, 0x20, 0x20, -0x30, 0x20, 0x37, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x0a, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x20, 0x37, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, 0x20, -0x20, 0x30, 0x20, 0x37, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x31, 0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x32, 0x37, 0x20, 0x20, 0x30, 0x20, 0x33, 0x37, 0x20, -0x34, 0x38, 0x20, 0x20, 0x31, 0x20, 0x31, 0x38, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x38, -0x20, 0x20, 0x30, 0x20, 0x38, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x38, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x34, -0x20, 0x20, 0x30, 0x20, 0x34, 0x36, 0x20, 0x20, 0x30, 0x20, 0x37, 0x32, -0x20, 0x0a, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, -0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x38, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, -0x39, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x39, 0x20, 0x31, 0x38, 0x20, 0x20, -0x31, 0x20, 0x0a, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x33, 0x20, 0x20, 0x30, 0x20, -0x36, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x35, 0x36, 0x20, 0x20, 0x30, 0x20, 0x37, 0x34, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x34, 0x37, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x36, 0x36, 0x20, 0x20, 0x30, -0x20, 0x38, 0x33, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x38, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x35, 0x20, 0x20, 0x30, -0x20, 0x35, 0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x39, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x39, 0x20, 0x20, 0x65, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x36, 0x37, 0x20, 0x20, 0x30, 0x20, 0x38, 0x35, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x38, 0x20, 0x20, -0x30, 0x20, 0x33, 0x39, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x39, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x34, 0x39, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x38, 0x36, 0x20, -0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x61, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x36, 0x38, 0x20, 0x20, 0x30, 0x20, 0x20, 0x61, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x20, -0x20, 0x30, 0x20, 0x31, 0x61, 0x20, 0x34, 0x34, 0x20, 0x20, 0x31, 0x20, -0x31, 0x38, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x63, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x61, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x61, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x39, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x39, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x33, -0x20, 0x20, 0x30, 0x20, 0x33, 0x61, 0x20, 0x0a, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x61, 0x20, 0x20, 0x30, 0x20, 0x39, -0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, -0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x62, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, -0x62, 0x20, 0x31, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x38, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x62, 0x32, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x36, 0x20, 0x20, 0x30, 0x20, -0x37, 0x37, 0x20, 0x20, 0x30, 0x20, 0x39, 0x34, 0x20, 0x20, 0x36, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x37, 0x20, 0x0a, 0x20, 0x30, -0x20, 0x37, 0x38, 0x20, 0x20, 0x30, 0x20, 0x61, 0x34, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x36, 0x39, 0x20, 0x20, 0x30, 0x20, 0x61, 0x35, 0x20, 0x20, 0x30, -0x20, 0x32, 0x62, 0x20, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x61, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x38, 0x38, 0x20, 0x20, 0x30, 0x20, 0x62, 0x33, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x62, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x39, 0x20, 0x20, -0x30, 0x20, 0x61, 0x36, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x36, 0x61, 0x20, 0x20, 0x30, 0x20, 0x62, 0x34, 0x20, 0x0a, -0x20, 0x30, 0x20, 0x63, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x63, 0x20, -0x20, 0x30, 0x20, 0x39, 0x38, 0x20, 0x20, 0x30, 0x20, 0x63, 0x31, 0x20, -0x33, 0x63, 0x20, 0x20, 0x31, 0x20, 0x31, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x63, 0x20, -0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x39, -0x20, 0x20, 0x30, 0x20, 0x62, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x35, 0x62, 0x20, 0x20, 0x30, 0x20, 0x63, 0x32, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x63, 0x20, 0x20, 0x30, 0x20, 0x33, 0x63, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x62, 0x36, 0x20, 0x20, 0x30, 0x20, 0x36, -0x62, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, -0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x63, 0x20, 0x31, 0x30, 0x20, 0x20, -0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, -0x38, 0x20, 0x20, 0x30, 0x20, 0x38, 0x61, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x64, 0x30, 0x20, 0x20, 0x30, 0x20, -0x20, 0x64, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x64, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x34, 0x62, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x39, 0x37, 0x20, 0x20, 0x30, 0x20, 0x61, 0x37, 0x20, 0x20, 0x63, 0x20, -0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x63, 0x33, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x61, 0x20, 0x20, 0x30, -0x20, 0x39, 0x39, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, 0x35, 0x20, 0x20, 0x30, -0x20, 0x35, 0x63, 0x20, 0x20, 0x30, 0x20, 0x62, 0x37, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x31, 0x64, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x64, 0x32, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x64, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x62, 0x20, 0x20, -0x30, 0x20, 0x64, 0x33, 0x20, 0x33, 0x34, 0x20, 0x20, 0x31, 0x20, 0x31, -0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x33, 0x64, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x63, 0x36, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x36, 0x63, 0x20, 0x20, 0x30, 0x20, 0x61, 0x39, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x61, 0x20, -0x20, 0x30, 0x20, 0x64, 0x34, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x62, 0x38, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x38, 0x62, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x64, -0x20, 0x20, 0x30, 0x20, 0x63, 0x37, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x63, -0x20, 0x20, 0x30, 0x20, 0x64, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x35, 0x64, 0x20, 0x20, 0x30, 0x20, 0x65, 0x30, -0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x65, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, -0x65, 0x20, 0x20, 0x30, 0x20, 0x32, 0x65, 0x20, 0x20, 0x30, 0x20, 0x65, -0x32, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, -0x65, 0x33, 0x20, 0x20, 0x30, 0x20, 0x36, 0x64, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x63, 0x20, 0x20, 0x30, 0x20, -0x65, 0x34, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x35, 0x20, 0x20, 0x30, 0x20, -0x62, 0x61, 0x20, 0x20, 0x30, 0x20, 0x66, 0x30, 0x20, 0x32, 0x36, 0x20, -0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x66, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x66, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x61, 0x20, 0x20, 0x30, -0x20, 0x39, 0x62, 0x20, 0x20, 0x30, 0x20, 0x62, 0x39, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x65, 0x20, 0x0a, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x36, 0x20, 0x20, -0x30, 0x20, 0x63, 0x38, 0x20, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x34, 0x65, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x64, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, 0x64, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x62, 0x20, 0x0a, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x65, 0x20, -0x20, 0x30, 0x20, 0x63, 0x39, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x66, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x63, 0x20, -0x20, 0x30, 0x20, 0x36, 0x65, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x66, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x66, 0x20, -0x0a, 0x32, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x38, -0x20, 0x20, 0x30, 0x20, 0x38, 0x64, 0x20, 0x20, 0x30, 0x20, 0x33, 0x66, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x66, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x65, 0x36, 0x20, 0x20, 0x30, 0x20, 0x63, -0x61, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, -0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x66, 0x20, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x62, 0x20, 0x20, 0x30, 0x20, 0x61, -0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, -0x37, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x66, 0x35, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x64, 0x39, 0x20, 0x20, 0x30, 0x20, 0x39, 0x64, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x66, 0x20, 0x20, 0x30, 0x20, -0x65, 0x38, 0x20, 0x31, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x63, 0x20, -0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x36, 0x66, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x36, 0x20, 0x20, 0x30, -0x20, 0x63, 0x62, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x63, 0x20, 0x20, 0x30, -0x20, 0x61, 0x64, 0x20, 0x20, 0x30, 0x20, 0x64, 0x61, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x66, 0x37, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x65, 0x20, 0x20, -0x30, 0x20, 0x37, 0x66, 0x20, 0x20, 0x30, 0x20, 0x38, 0x65, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x65, 0x20, 0x20, -0x30, 0x20, 0x61, 0x65, 0x20, 0x20, 0x30, 0x20, 0x63, 0x63, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x66, 0x38, 0x20, -0x20, 0x30, 0x20, 0x38, 0x66, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x62, 0x20, -0x20, 0x30, 0x20, 0x62, 0x64, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x65, 0x61, 0x20, 0x20, 0x30, 0x20, 0x66, 0x39, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x39, 0x66, 0x20, 0x20, 0x30, 0x20, 0x65, 0x62, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x65, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, 0x64, -0x20, 0x20, 0x30, 0x20, 0x66, 0x61, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x64, 0x64, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x65, -0x63, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, -0x39, 0x20, 0x20, 0x30, 0x20, 0x61, 0x66, 0x20, 0x20, 0x30, 0x20, 0x64, -0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, -0x65, 0x20, 0x20, 0x30, 0x20, 0x66, 0x62, 0x20, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x66, 0x20, 0x20, 0x30, 0x20, -0x64, 0x65, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x63, 0x66, 0x20, 0x20, 0x30, 0x20, 0x65, 0x65, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x64, 0x66, 0x20, 0x20, 0x30, 0x20, 0x65, 0x66, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x66, 0x20, 0x0a, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x64, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x64, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x63, 0x20, 0x20, 0x30, -0x20, 0x66, 0x65, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, -0x20, 0x31, 0x34, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, -0x30, 0x20, 0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, -0x74, 0x61, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x31, -0x35, 0x20, 0x35, 0x31, 0x31, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, -0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, -0x0a, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, -0x32, 0x20, 0x33, 0x32, 0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, -0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x20, 0x30, 0x20, 0x33, -0x31, 0x20, 0x0a, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x33, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x33, 0x20, 0x20, 0x30, 0x20, -0x34, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x33, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x33, 0x20, 0x20, 0x65, 0x20, -0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x34, 0x20, 0x20, 0x30, 0x20, 0x31, 0x34, 0x20, 0x20, 0x30, -0x20, 0x34, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x33, 0x20, 0x20, 0x30, -0x20, 0x34, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x32, 0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x33, 0x20, 0x20, 0x61, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x34, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x30, 0x20, 0x20, -0x30, 0x20, 0x20, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x35, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x35, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x35, 0x32, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x32, 0x35, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x34, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x33, 0x20, -0x20, 0x30, 0x20, 0x36, 0x31, 0x20, 0x35, 0x61, 0x20, 0x20, 0x31, 0x20, -0x32, 0x34, 0x20, 0x20, 0x31, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x33, 0x35, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x36, 0x20, 0x20, 0x30, 0x20, 0x36, 0x32, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x36, 0x20, 0x20, 0x30, 0x20, 0x35, 0x34, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, -0x35, 0x20, 0x20, 0x30, 0x20, 0x36, 0x33, 0x20, 0x20, 0x61, 0x20, 0x20, -0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, -0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, -0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, 0x20, 0x0a, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x31, 0x37, 0x20, 0x20, 0x30, 0x20, 0x36, 0x34, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x32, 0x20, 0x20, 0x30, 0x20, -0x32, 0x37, 0x20, 0x31, 0x38, 0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, -0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, -0x20, 0x34, 0x36, 0x20, 0x20, 0x30, 0x20, 0x37, 0x33, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x37, 0x20, 0x20, 0x30, -0x20, 0x36, 0x35, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x36, 0x20, 0x20, 0x30, -0x20, 0x38, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x38, 0x20, 0x20, 0x30, 0x20, 0x37, 0x34, 0x20, 0x0a, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x38, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x38, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x32, 0x20, 0x20, -0x30, 0x20, 0x32, 0x38, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, -0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x37, 0x20, 0x0a, -0x20, 0x30, 0x20, 0x36, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x38, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x38, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x37, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x37, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x34, 0x20, -0x20, 0x30, 0x20, 0x34, 0x38, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x39, 0x30, 0x20, 0x20, 0x30, 0x20, 0x31, 0x39, -0x20, 0x20, 0x30, 0x20, 0x39, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x32, -0x20, 0x20, 0x30, 0x20, 0x37, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x36, 0x37, 0x20, 0x20, 0x30, 0x20, 0x32, 0x39, -0x20, 0x0a, 0x35, 0x63, 0x20, 0x20, 0x31, 0x20, 0x32, 0x34, 0x20, 0x20, -0x31, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x61, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, -0x38, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x39, 0x20, 0x20, 0x30, 0x20, 0x37, -0x37, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x39, 0x33, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x33, 0x39, 0x20, 0x20, 0x30, 0x20, 0x39, 0x34, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x39, 0x20, 0x20, 0x30, 0x20, -0x38, 0x36, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x36, 0x38, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x61, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x61, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x20, 0x20, 0x30, -0x20, 0x31, 0x61, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x32, 0x20, 0x20, 0x30, -0x20, 0x32, 0x61, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x39, 0x35, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x35, 0x39, 0x20, 0x31, -0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x61, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x33, 0x61, 0x20, 0x20, 0x30, 0x20, 0x38, 0x37, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x37, 0x38, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x61, 0x34, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x61, 0x20, -0x20, 0x30, 0x20, 0x39, 0x36, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x36, 0x39, 0x20, 0x20, 0x30, 0x20, 0x62, 0x30, 0x20, -0x20, 0x30, 0x20, 0x62, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x31, 0x62, -0x20, 0x20, 0x30, 0x20, 0x61, 0x35, 0x20, 0x20, 0x30, 0x20, 0x62, 0x32, -0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x35, 0x61, 0x20, 0x20, 0x30, 0x20, 0x32, 0x62, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x38, -0x20, 0x20, 0x30, 0x20, 0x39, 0x37, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x39, 0x20, 0x20, 0x30, 0x20, 0x33, -0x62, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, -0x61, 0x20, 0x20, 0x30, 0x20, 0x62, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x62, 0x20, 0x0a, 0x20, 0x30, 0x20, -0x63, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x38, 0x20, 0x20, 0x30, 0x20, -0x38, 0x39, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x31, 0x63, 0x20, 0x20, 0x30, 0x20, 0x62, 0x35, 0x20, 0x35, 0x30, 0x20, -0x20, 0x31, 0x20, 0x32, 0x32, 0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, -0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x35, 0x62, 0x20, 0x20, 0x30, 0x20, 0x32, 0x63, 0x20, 0x20, 0x30, -0x20, 0x63, 0x32, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x62, 0x20, 0x20, 0x30, 0x20, 0x63, 0x30, 0x20, 0x20, 0x30, -0x20, 0x61, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x61, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, 0x61, 0x20, 0x20, -0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, 0x33, 0x20, 0x20, -0x30, 0x20, 0x33, 0x63, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x63, 0x20, 0x20, -0x30, 0x20, 0x39, 0x39, 0x20, 0x20, 0x30, 0x20, 0x62, 0x36, 0x20, 0x0a, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x36, 0x62, 0x20, 0x20, 0x30, 0x20, 0x63, 0x34, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x63, 0x20, -0x20, 0x30, 0x20, 0x61, 0x38, 0x20, 0x31, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x61, 0x20, -0x0a, 0x20, 0x30, 0x20, 0x63, 0x35, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x30, -0x20, 0x20, 0x30, 0x20, 0x35, 0x63, 0x20, 0x20, 0x30, 0x20, 0x64, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x62, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, 0x62, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x64, -0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, -0x64, 0x20, 0x20, 0x30, 0x20, 0x32, 0x64, 0x20, 0x20, 0x63, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x32, 0x20, 0x20, 0x30, 0x20, 0x64, -0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x64, 0x20, 0x20, 0x30, 0x20, 0x63, -0x36, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x36, 0x63, 0x20, 0x20, 0x30, 0x20, 0x61, 0x39, 0x20, 0x20, 0x36, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x61, 0x20, 0x20, 0x30, 0x20, -0x62, 0x38, 0x20, 0x20, 0x30, 0x20, 0x64, 0x34, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x38, 0x62, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x64, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, 0x37, 0x20, 0x20, 0x30, -0x20, 0x37, 0x63, 0x20, 0x34, 0x34, 0x20, 0x20, 0x31, 0x20, 0x32, 0x32, -0x20, 0x20, 0x31, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x61, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x35, 0x20, 0x20, 0x30, -0x20, 0x35, 0x64, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x30, 0x20, 0x20, -0x30, 0x20, 0x20, 0x65, 0x20, 0x20, 0x30, 0x20, 0x65, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x65, 0x20, 0x20, 0x30, 0x20, 0x65, 0x32, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x61, 0x20, 0x20, -0x30, 0x20, 0x32, 0x65, 0x20, 0x0a, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x62, 0x39, 0x20, 0x20, 0x30, 0x20, 0x39, 0x62, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x33, 0x20, -0x20, 0x30, 0x20, 0x64, 0x36, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x64, 0x20, -0x20, 0x30, 0x20, 0x33, 0x65, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x63, 0x38, 0x20, 0x20, 0x30, 0x20, 0x38, 0x63, -0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x65, 0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x65, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x37, -0x20, 0x20, 0x30, 0x20, 0x37, 0x64, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, -0x35, 0x20, 0x20, 0x30, 0x20, 0x62, 0x61, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x62, 0x20, 0x20, 0x30, 0x20, 0x35, -0x65, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, -0x39, 0x20, 0x20, 0x30, 0x20, 0x39, 0x63, 0x20, 0x0a, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x31, 0x20, 0x20, 0x30, 0x20, -0x31, 0x66, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x66, 0x30, 0x20, 0x20, 0x30, 0x20, 0x36, 0x65, 0x20, 0x20, 0x30, 0x20, -0x66, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x32, 0x66, 0x20, 0x20, 0x30, 0x20, 0x65, 0x36, 0x20, 0x0a, 0x32, 0x36, -0x20, 0x20, 0x31, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x38, 0x20, 0x20, 0x30, -0x20, 0x66, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x33, 0x66, 0x20, 0x20, 0x30, 0x20, 0x66, 0x34, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x34, 0x66, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x38, 0x64, 0x20, 0x20, 0x30, 0x20, 0x64, 0x39, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x62, 0x20, 0x20, -0x30, 0x20, 0x63, 0x61, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x61, 0x63, 0x20, 0x20, 0x30, 0x20, 0x65, 0x37, 0x20, 0x0a, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x65, 0x20, -0x20, 0x30, 0x20, 0x66, 0x35, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x39, 0x64, 0x20, 0x20, 0x30, 0x20, 0x35, 0x66, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x38, 0x20, -0x20, 0x30, 0x20, 0x38, 0x65, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x30, 0x20, 0x66, 0x36, 0x20, 0x20, 0x30, 0x20, 0x63, 0x62, -0x20, 0x32, 0x32, 0x20, 0x20, 0x31, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x20, 0x66, 0x20, 0x20, 0x30, 0x20, 0x61, 0x65, -0x20, 0x20, 0x30, 0x20, 0x36, 0x66, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x62, 0x63, 0x20, 0x20, 0x30, 0x20, 0x64, -0x61, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x64, 0x20, 0x20, 0x30, 0x20, 0x66, -0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, -0x66, 0x20, 0x20, 0x30, 0x20, 0x65, 0x39, 0x20, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x39, 0x65, 0x20, 0x20, 0x30, 0x20, -0x63, 0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x66, 0x38, 0x20, 0x20, 0x30, 0x20, 0x38, 0x66, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x64, 0x62, 0x20, 0x20, 0x30, 0x20, 0x62, 0x64, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x61, 0x20, 0x20, 0x30, 0x20, -0x66, 0x39, 0x20, 0x0a, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x66, 0x20, 0x20, 0x30, -0x20, 0x64, 0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x63, 0x64, 0x20, 0x20, 0x30, 0x20, 0x65, 0x62, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x62, 0x65, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x66, 0x61, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x66, 0x20, 0x20, -0x30, 0x20, 0x64, 0x64, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x63, 0x20, 0x20, -0x30, 0x20, 0x63, 0x65, 0x20, 0x20, 0x30, 0x20, 0x66, 0x62, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x62, 0x66, 0x20, 0x20, 0x30, 0x20, 0x65, 0x64, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x65, 0x20, -0x20, 0x30, 0x20, 0x66, 0x63, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x63, 0x66, 0x20, 0x20, 0x30, 0x20, 0x66, 0x64, 0x20, -0x20, 0x30, 0x20, 0x65, 0x65, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x66, -0x20, 0x20, 0x30, 0x20, 0x66, 0x65, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x65, 0x66, 0x20, 0x20, 0x30, 0x20, 0x66, 0x66, -0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x31, 0x36, -0x20, 0x35, 0x31, 0x31, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, 0x20, -0x31, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, -0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x31, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, -0x32, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x30, 0x20, 0x32, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x32, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x32, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x33, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x33, -0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x33, 0x20, 0x20, 0x61, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, -0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, -0x34, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x31, 0x20, 0x20, 0x36, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x31, 0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x33, 0x33, 0x20, 0x20, 0x30, 0x20, 0x34, 0x32, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x32, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x30, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x33, 0x20, 0x20, 0x30, -0x20, 0x33, 0x34, 0x20, 0x38, 0x61, 0x20, 0x20, 0x31, 0x20, 0x32, 0x38, -0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x35, 0x20, 0x20, 0x30, -0x20, 0x31, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x31, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x35, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x35, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x34, 0x34, 0x20, 0x20, 0x30, 0x20, 0x33, 0x35, 0x20, 0x20, -0x30, 0x20, 0x35, 0x33, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x36, 0x30, 0x20, -0x20, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x30, 0x20, 0x36, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x36, 0x20, -0x20, 0x30, 0x20, 0x36, 0x32, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x32, 0x36, 0x20, 0x20, 0x30, 0x20, 0x35, 0x34, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x35, -0x20, 0x20, 0x30, 0x20, 0x36, 0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x36, -0x20, 0x20, 0x30, 0x20, 0x37, 0x30, 0x20, 0x20, 0x30, 0x20, 0x37, 0x31, -0x20, 0x32, 0x38, 0x20, 0x20, 0x31, 0x20, 0x31, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x37, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x37, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x35, 0x20, 0x20, 0x30, 0x20, 0x36, -0x34, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, -0x37, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x36, 0x20, 0x0a, 0x20, 0x30, 0x20, -0x36, 0x35, 0x20, 0x20, 0x30, 0x20, 0x37, 0x33, 0x20, 0x20, 0x61, 0x20, -0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x37, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x36, 0x20, 0x20, 0x30, 0x20, -0x20, 0x38, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x38, 0x30, 0x20, 0x20, 0x30, 0x20, 0x38, 0x31, 0x20, 0x0a, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x31, 0x38, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x37, 0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x37, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x32, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x38, 0x20, 0x20, 0x30, -0x20, 0x36, 0x36, 0x20, 0x31, 0x38, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, -0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x38, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x38, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x35, 0x20, 0x20, -0x30, 0x20, 0x38, 0x34, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x38, 0x20, 0x0a, -0x20, 0x30, 0x20, 0x39, 0x30, 0x20, 0x20, 0x30, 0x20, 0x39, 0x31, 0x20, -0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x31, 0x39, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x20, 0x39, 0x20, 0x20, 0x30, 0x20, 0x37, 0x36, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x32, 0x20, -0x20, 0x30, 0x20, 0x32, 0x39, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x35, -0x20, 0x20, 0x30, 0x20, 0x35, 0x38, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x39, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x39, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x61, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x61, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x31, 0x61, 0x20, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, -0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, -0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, -0x37, 0x20, 0x20, 0x30, 0x20, 0x34, 0x39, 0x20, 0x20, 0x36, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, -0x34, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x37, 0x37, 0x20, 0x20, 0x30, 0x20, 0x38, 0x36, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x38, 0x20, 0x20, 0x30, 0x20, -0x39, 0x35, 0x20, 0x64, 0x63, 0x20, 0x20, 0x31, 0x20, 0x37, 0x65, 0x20, -0x20, 0x31, 0x20, 0x33, 0x32, 0x20, 0x20, 0x31, 0x20, 0x31, 0x61, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x32, 0x61, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x35, 0x39, 0x20, 0x20, 0x30, 0x20, 0x33, 0x61, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x33, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x37, 0x20, 0x20, 0x30, -0x20, 0x37, 0x38, 0x20, 0x0a, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x61, 0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x61, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x36, 0x20, 0x20, -0x30, 0x20, 0x36, 0x39, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x30, 0x20, 0x20, -0x30, 0x20, 0x20, 0x62, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x62, 0x31, 0x20, -0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x62, 0x20, -0x20, 0x30, 0x20, 0x62, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x32, 0x62, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x61, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x61, 0x20, -0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x62, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x61, 0x36, 0x20, 0x20, 0x30, 0x20, 0x36, 0x61, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x62, 0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x62, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x63, -0x20, 0x20, 0x30, 0x20, 0x63, 0x31, 0x20, 0x0a, 0x31, 0x65, 0x20, 0x20, -0x31, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x35, 0x20, 0x20, 0x30, 0x20, 0x63, -0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x63, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, -0x37, 0x20, 0x20, 0x30, 0x20, 0x63, 0x33, 0x20, 0x0a, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x62, 0x20, 0x20, 0x30, 0x20, -0x63, 0x34, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x64, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x38, 0x38, 0x20, 0x20, 0x30, 0x20, 0x39, 0x37, 0x20, 0x20, 0x30, 0x20, -0x33, 0x62, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x31, 0x20, 0x20, 0x30, -0x20, 0x64, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x32, 0x64, 0x20, 0x20, 0x30, 0x20, 0x64, 0x33, 0x20, 0x31, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x31, 0x65, 0x20, 0x20, 0x30, 0x20, 0x32, 0x65, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x65, 0x32, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x37, 0x39, 0x20, 0x20, 0x30, 0x20, 0x39, 0x38, 0x20, 0x20, -0x30, 0x20, 0x63, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x38, 0x39, 0x20, 0x20, 0x30, 0x20, 0x35, 0x62, 0x20, 0x0a, -0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x63, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x61, 0x20, -0x20, 0x30, 0x20, 0x62, 0x36, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x63, 0x20, -0x20, 0x30, 0x20, 0x39, 0x39, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x30, 0x20, 0x61, 0x38, 0x20, 0x20, 0x30, 0x20, 0x38, 0x61, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x20, 0x64, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x63, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x63, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x33, 0x64, 0x20, 0x20, 0x30, 0x20, 0x63, 0x36, -0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, -0x63, 0x20, 0x20, 0x30, 0x20, 0x39, 0x61, 0x20, 0x35, 0x38, 0x20, 0x20, -0x31, 0x20, 0x35, 0x36, 0x20, 0x20, 0x31, 0x20, 0x32, 0x34, 0x20, 0x20, -0x31, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x62, 0x20, 0x20, 0x30, 0x20, 0x34, -0x64, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x63, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, 0x63, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x64, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x64, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x30, 0x20, 0x20, 0x30, 0x20, -0x20, 0x65, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x65, 0x33, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x64, 0x30, 0x20, 0x20, 0x30, 0x20, 0x62, 0x37, 0x20, 0x20, 0x30, -0x20, 0x37, 0x62, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x61, 0x39, 0x20, 0x20, 0x30, 0x20, 0x62, 0x38, 0x20, 0x20, 0x30, -0x20, 0x64, 0x34, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x65, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x61, 0x61, 0x20, 0x20, 0x30, 0x20, 0x62, 0x39, 0x20, 0x31, -0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x62, 0x20, 0x20, -0x30, 0x20, 0x64, 0x36, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x36, 0x64, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x65, 0x20, -0x20, 0x30, 0x20, 0x63, 0x38, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x38, 0x63, 0x20, 0x20, 0x30, 0x20, 0x65, 0x34, 0x20, -0x20, 0x30, 0x20, 0x34, 0x65, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x64, 0x37, -0x20, 0x20, 0x30, 0x20, 0x65, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x62, 0x61, 0x20, 0x20, 0x30, 0x20, 0x61, 0x62, -0x20, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x63, -0x20, 0x20, 0x30, 0x20, 0x65, 0x36, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x36, -0x65, 0x20, 0x20, 0x30, 0x20, 0x64, 0x38, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x64, 0x20, 0x20, 0x30, 0x20, 0x62, -0x62, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, -0x37, 0x20, 0x20, 0x30, 0x20, 0x39, 0x64, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x38, 0x20, 0x0a, 0x20, 0x30, 0x20, -0x38, 0x65, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, 0x62, 0x20, 0x20, 0x30, 0x20, -0x62, 0x63, 0x20, 0x20, 0x30, 0x20, 0x39, 0x65, 0x20, 0x20, 0x30, 0x20, -0x66, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x31, 0x66, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x66, 0x20, 0x20, 0x30, 0x20, 0x32, 0x66, 0x20, 0x0a, 0x34, 0x32, -0x20, 0x20, 0x31, 0x20, 0x33, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x32, 0x20, 0x33, 0x34, -0x20, 0x20, 0x31, 0x20, 0x33, 0x32, 0x20, 0x20, 0x31, 0x20, 0x31, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x64, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x65, 0x20, 0x0a, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x64, 0x20, 0x20, -0x30, 0x20, 0x63, 0x39, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, 0x61, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x63, 0x20, 0x20, -0x30, 0x20, 0x37, 0x65, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x61, 0x20, 0x0a, -0x20, 0x30, 0x20, 0x61, 0x64, 0x20, 0x20, 0x30, 0x20, 0x63, 0x63, 0x20, -0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x65, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x62, 0x20, -0x20, 0x30, 0x20, 0x64, 0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x63, 0x64, 0x20, 0x20, 0x30, 0x20, 0x62, 0x65, 0x20, -0x0a, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x62, -0x20, 0x20, 0x30, 0x20, 0x65, 0x64, 0x20, 0x20, 0x30, 0x20, 0x65, 0x65, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x39, -0x20, 0x20, 0x30, 0x20, 0x65, 0x61, 0x20, 0x20, 0x30, 0x20, 0x65, 0x39, -0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, -0x65, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x64, 0x20, 0x20, 0x30, 0x20, 0x65, -0x63, 0x20, 0x20, 0x30, 0x20, 0x63, 0x65, 0x20, 0x20, 0x30, 0x20, 0x33, -0x66, 0x20, 0x20, 0x30, 0x20, 0x66, 0x30, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, -0x33, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x66, 0x34, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x66, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x35, 0x20, 0x20, 0x30, 0x20, -0x35, 0x66, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x66, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x66, 0x36, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x36, 0x66, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x37, 0x20, 0x20, 0x30, -0x20, 0x37, 0x66, 0x20, 0x20, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x38, 0x66, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x66, 0x38, 0x20, 0x20, 0x30, 0x20, 0x66, 0x39, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x39, 0x66, 0x20, 0x20, 0x30, 0x20, 0x66, 0x61, 0x20, 0x20, -0x30, 0x20, 0x61, 0x66, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x66, 0x62, 0x20, 0x20, 0x30, 0x20, 0x62, 0x66, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x63, 0x20, 0x20, -0x30, 0x20, 0x63, 0x66, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x64, 0x20, -0x20, 0x30, 0x20, 0x64, 0x66, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x66, 0x65, 0x20, 0x20, 0x30, 0x20, 0x65, 0x66, 0x20, -0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x31, 0x37, 0x20, -0x35, 0x31, 0x31, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, 0x20, 0x32, -0x0a, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, -0x31, 0x36, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x31, -0x38, 0x20, 0x35, 0x31, 0x31, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, -0x20, 0x33, 0x0a, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, -0x65, 0x20, 0x31, 0x36, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, -0x20, 0x31, 0x39, 0x20, 0x35, 0x31, 0x31, 0x20, 0x31, 0x36, 0x20, 0x31, -0x36, 0x20, 0x20, 0x34, 0x0a, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, -0x6e, 0x63, 0x65, 0x20, 0x31, 0x36, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, -0x6c, 0x65, 0x20, 0x32, 0x30, 0x20, 0x35, 0x31, 0x31, 0x20, 0x31, 0x36, -0x20, 0x31, 0x36, 0x20, 0x20, 0x36, 0x0a, 0x2e, 0x72, 0x65, 0x66, 0x65, -0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x31, 0x36, 0x0a, 0x0a, 0x2e, 0x74, -0x61, 0x62, 0x6c, 0x65, 0x20, 0x32, 0x31, 0x20, 0x35, 0x31, 0x31, 0x20, -0x31, 0x36, 0x20, 0x31, 0x36, 0x20, 0x20, 0x38, 0x0a, 0x2e, 0x72, 0x65, -0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x31, 0x36, 0x0a, 0x0a, -0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x32, 0x32, 0x20, 0x35, 0x31, -0x31, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, 0x31, 0x30, 0x0a, 0x2e, -0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x31, 0x36, -0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x32, 0x33, 0x20, -0x35, 0x31, 0x31, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, 0x31, 0x33, -0x0a, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, -0x31, 0x36, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x32, -0x34, 0x20, 0x35, 0x31, 0x32, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, -0x20, 0x34, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, -0x0a, 0x33, 0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x31, 0x30, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x31, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, -0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, -0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, -0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x33, 0x20, 0x20, 0x65, 0x20, 0x20, -0x31, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x31, 0x20, 0x20, 0x30, 0x20, -0x31, 0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x32, 0x20, 0x20, 0x30, 0x20, -0x32, 0x33, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x30, 0x20, 0x20, 0x30, 0x20, -0x20, 0x34, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x34, 0x20, 0x20, 0x30, -0x20, 0x33, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x34, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x34, 0x20, 0x20, 0x36, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x34, 0x33, 0x20, 0x20, -0x30, 0x20, 0x33, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x30, 0x20, 0x20, -0x30, 0x20, 0x20, 0x35, 0x20, 0x20, 0x30, 0x20, 0x31, 0x35, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x32, 0x20, 0x20, -0x30, 0x20, 0x32, 0x35, 0x20, 0x0a, 0x66, 0x61, 0x20, 0x20, 0x31, 0x20, -0x36, 0x32, 0x20, 0x20, 0x31, 0x20, 0x32, 0x32, 0x20, 0x20, 0x31, 0x20, -0x31, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, -0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x34, 0x34, 0x20, 0x20, 0x30, 0x20, 0x35, 0x33, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x35, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x36, 0x30, -0x20, 0x20, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x36, 0x32, 0x20, 0x20, 0x30, 0x20, 0x32, 0x36, -0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x35, -0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, -0x36, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, -0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, -0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x36, 0x20, 0x0a, 0x32, 0x30, 0x20, -0x20, 0x31, 0x20, 0x20, 0x65, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x37, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x32, 0x37, 0x20, 0x20, 0x30, 0x20, 0x33, 0x37, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x33, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, -0x20, 0x37, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x37, 0x20, 0x20, 0x30, -0x20, 0x31, 0x37, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x36, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x36, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x38, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x38, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x38, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x34, 0x20, 0x20, -0x30, 0x20, 0x34, 0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x31, 0x38, 0x20, 0x20, 0x30, 0x20, 0x38, 0x32, 0x20, 0x31, -0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, -0x20, 0x30, 0x20, 0x32, 0x38, 0x20, 0x20, 0x30, 0x20, 0x36, 0x36, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x33, 0x20, -0x20, 0x30, 0x20, 0x33, 0x38, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x35, 0x20, -0x20, 0x30, 0x20, 0x35, 0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x38, 0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x38, 0x20, -0x0a, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x31, -0x20, 0x20, 0x30, 0x20, 0x31, 0x39, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x39, 0x32, 0x20, 0x20, 0x30, 0x20, 0x37, 0x36, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x36, 0x37, 0x20, 0x20, 0x30, 0x20, 0x32, 0x39, -0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, -0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x38, 0x20, 0x35, 0x63, 0x20, 0x20, -0x31, 0x20, 0x32, 0x32, 0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, -0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, -0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x39, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x39, 0x34, 0x20, 0x20, 0x30, 0x20, -0x34, 0x39, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x37, 0x20, 0x20, 0x30, 0x20, -0x38, 0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x36, 0x38, 0x20, 0x20, 0x30, 0x20, 0x61, 0x31, 0x20, 0x20, 0x38, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x61, 0x32, 0x20, 0x20, 0x30, -0x20, 0x32, 0x61, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x39, 0x35, 0x20, 0x20, 0x30, 0x20, 0x35, 0x39, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x61, 0x33, 0x20, 0x20, 0x30, 0x20, 0x33, 0x61, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x37, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x37, 0x38, 0x20, 0x20, -0x30, 0x20, 0x34, 0x61, 0x20, 0x31, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, -0x63, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x34, 0x20, 0x20, -0x30, 0x20, 0x39, 0x36, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x36, 0x39, 0x20, 0x20, -0x30, 0x20, 0x62, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x31, 0x62, 0x20, 0x20, 0x30, 0x20, 0x61, 0x35, 0x20, -0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x62, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x35, 0x61, 0x20, 0x20, 0x30, 0x20, 0x32, 0x62, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x38, 0x20, -0x20, 0x30, 0x20, 0x62, 0x33, 0x20, 0x0a, 0x31, 0x30, 0x20, 0x20, 0x31, -0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x30, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x39, -0x20, 0x20, 0x30, 0x20, 0x61, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x39, 0x37, 0x20, 0x20, 0x30, 0x20, 0x37, 0x39, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x36, 0x20, 0x20, 0x30, 0x20, 0x36, -0x61, 0x20, 0x20, 0x30, 0x20, 0x62, 0x34, 0x20, 0x20, 0x63, 0x20, 0x20, -0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x61, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x61, 0x20, 0x20, 0x30, 0x20, 0x62, -0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, -0x33, 0x62, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x62, 0x20, 0x20, 0x30, 0x20, 0x63, 0x30, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x34, 0x62, 0x20, 0x20, 0x30, 0x20, 0x63, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x38, 0x20, 0x20, 0x30, 0x20, -0x38, 0x39, 0x20, 0x34, 0x33, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x32, 0x32, -0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x63, 0x20, 0x20, 0x30, -0x20, 0x62, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x35, 0x62, 0x20, 0x20, 0x30, 0x20, 0x63, 0x32, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x32, 0x63, 0x20, 0x20, 0x30, 0x20, 0x61, 0x37, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x61, 0x20, 0x20, -0x30, 0x20, 0x63, 0x33, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, -0x36, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x33, 0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x20, 0x63, 0x20, 0x20, 0x30, 0x20, 0x64, 0x30, 0x20, 0x0a, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x36, 0x20, -0x20, 0x30, 0x20, 0x36, 0x62, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, 0x34, 0x20, -0x20, 0x30, 0x20, 0x34, 0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x39, 0x39, 0x20, 0x20, 0x30, 0x20, 0x61, 0x38, 0x20, -0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, -0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x38, 0x61, 0x20, 0x20, 0x30, 0x20, 0x63, 0x35, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x35, 0x63, -0x20, 0x20, 0x30, 0x20, 0x64, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x37, -0x20, 0x20, 0x30, 0x20, 0x37, 0x62, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x31, 0x64, 0x20, 0x20, 0x30, 0x20, 0x64, -0x32, 0x20, 0x20, 0x39, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, -0x64, 0x20, 0x20, 0x30, 0x20, 0x64, 0x33, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x64, 0x20, 0x20, 0x30, 0x20, 0x63, -0x36, 0x20, 0x35, 0x35, 0x20, 0x66, 0x61, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x36, 0x63, 0x20, 0x20, 0x30, 0x20, 0x61, 0x39, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x61, 0x20, 0x20, 0x30, 0x20, -0x64, 0x34, 0x20, 0x32, 0x30, 0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, -0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x62, 0x38, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x38, 0x62, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x34, 0x64, 0x20, 0x20, 0x30, -0x20, 0x63, 0x37, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x37, 0x63, 0x20, 0x20, 0x30, -0x20, 0x64, 0x35, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x35, 0x64, 0x20, 0x20, 0x30, 0x20, 0x65, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x31, 0x65, 0x20, 0x20, -0x30, 0x20, 0x65, 0x32, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x61, 0x61, 0x20, 0x20, 0x30, 0x20, 0x62, 0x39, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x39, 0x62, 0x20, 0x20, 0x30, 0x20, 0x65, 0x33, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x64, 0x36, 0x20, -0x20, 0x30, 0x20, 0x36, 0x64, 0x20, 0x31, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x36, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x33, 0x65, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x32, 0x65, 0x20, -0x20, 0x30, 0x20, 0x34, 0x65, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x63, 0x38, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x38, 0x63, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x65, 0x34, 0x20, 0x20, 0x30, 0x20, 0x64, 0x37, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x37, 0x64, 0x20, 0x20, 0x30, 0x20, 0x61, 0x62, -0x20, 0x20, 0x30, 0x20, 0x65, 0x35, 0x20, 0x20, 0x61, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x61, 0x20, 0x20, 0x30, 0x20, 0x35, -0x65, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, -0x39, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, -0x63, 0x20, 0x20, 0x30, 0x20, 0x36, 0x65, 0x20, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, -0x36, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, -0x20, 0x64, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x65, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x65, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x64, 0x38, 0x20, 0x20, 0x30, 0x20, 0x38, 0x64, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x62, 0x62, 0x20, 0x20, 0x30, 0x20, -0x63, 0x61, 0x20, 0x34, 0x61, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x66, 0x20, 0x34, 0x30, -0x20, 0x20, 0x31, 0x20, 0x33, 0x61, 0x20, 0x20, 0x31, 0x20, 0x32, 0x30, -0x20, 0x20, 0x31, 0x20, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, -0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x63, 0x20, 0x20, 0x30, -0x20, 0x65, 0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, -0x30, 0x20, 0x37, 0x65, 0x20, 0x20, 0x30, 0x20, 0x64, 0x39, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x39, 0x64, 0x20, 0x20, 0x30, 0x20, 0x65, 0x38, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x38, 0x65, 0x20, 0x20, -0x30, 0x20, 0x63, 0x62, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, -0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x0a, -0x20, 0x30, 0x20, 0x62, 0x63, 0x20, 0x20, 0x30, 0x20, 0x64, 0x61, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x61, 0x64, 0x20, -0x20, 0x30, 0x20, 0x65, 0x39, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x65, 0x20, -0x20, 0x30, 0x20, 0x63, 0x63, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x64, 0x62, 0x20, 0x20, 0x30, 0x20, 0x62, 0x64, 0x20, -0x0a, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x65, 0x61, 0x20, 0x20, 0x30, 0x20, 0x61, 0x65, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x63, -0x20, 0x20, 0x30, 0x20, 0x63, 0x64, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x65, 0x62, -0x20, 0x0a, 0x20, 0x30, 0x20, 0x62, 0x65, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x64, 0x20, 0x20, 0x30, 0x20, 0x65, -0x63, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, -0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x63, -0x65, 0x20, 0x20, 0x30, 0x20, 0x65, 0x64, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x64, 0x65, 0x20, 0x20, 0x30, 0x20, 0x65, -0x65, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x20, 0x66, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x66, 0x30, 0x20, 0x20, 0x30, 0x20, 0x31, 0x66, 0x20, 0x20, 0x30, 0x20, -0x66, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x32, 0x20, 0x20, 0x30, 0x20, -0x32, 0x66, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x66, 0x33, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x33, 0x66, 0x20, 0x31, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x66, 0x34, 0x20, 0x20, 0x30, 0x20, 0x34, 0x66, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x35, 0x20, 0x20, 0x30, -0x20, 0x35, 0x66, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x66, 0x36, 0x20, 0x20, -0x30, 0x20, 0x36, 0x66, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x66, 0x37, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x37, 0x66, 0x20, 0x20, 0x30, 0x20, 0x38, 0x66, 0x20, 0x20, -0x61, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x38, 0x20, 0x20, -0x30, 0x20, 0x66, 0x39, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x39, 0x66, 0x20, -0x20, 0x30, 0x20, 0x61, 0x66, 0x20, 0x20, 0x30, 0x20, 0x66, 0x61, 0x20, -0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, -0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x62, 0x20, -0x20, 0x30, 0x20, 0x62, 0x66, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, -0x20, 0x30, 0x20, 0x66, 0x63, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x63, 0x66, -0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, -0x20, 0x20, 0x30, 0x20, 0x66, 0x64, 0x20, 0x20, 0x30, 0x20, 0x64, 0x66, -0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x66, 0x65, -0x20, 0x20, 0x30, 0x20, 0x65, 0x66, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, -0x62, 0x6c, 0x65, 0x20, 0x32, 0x35, 0x20, 0x35, 0x31, 0x32, 0x20, 0x31, -0x36, 0x20, 0x31, 0x36, 0x20, 0x20, 0x35, 0x0a, 0x2e, 0x72, 0x65, 0x66, -0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x32, 0x34, 0x0a, 0x0a, 0x2e, -0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x32, 0x36, 0x20, 0x35, 0x31, 0x32, -0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, 0x20, 0x36, 0x0a, 0x2e, 0x72, -0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x32, 0x34, 0x0a, -0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x32, 0x37, 0x20, 0x35, -0x31, 0x32, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, 0x20, 0x37, 0x0a, -0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x32, -0x34, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x32, 0x38, -0x20, 0x35, 0x31, 0x32, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, 0x20, 0x20, -0x38, 0x0a, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, -0x20, 0x32, 0x34, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, -0x32, 0x39, 0x20, 0x35, 0x31, 0x32, 0x20, 0x31, 0x36, 0x20, 0x31, 0x36, -0x20, 0x20, 0x39, 0x0a, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, -0x63, 0x65, 0x20, 0x32, 0x34, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, -0x65, 0x20, 0x33, 0x30, 0x20, 0x35, 0x31, 0x32, 0x20, 0x31, 0x36, 0x20, -0x31, 0x36, 0x20, 0x31, 0x31, 0x0a, 0x2e, 0x72, 0x65, 0x66, 0x65, 0x72, -0x65, 0x6e, 0x63, 0x65, 0x20, 0x32, 0x34, 0x0a, 0x0a, 0x2e, 0x74, 0x61, -0x62, 0x6c, 0x65, 0x20, 0x33, 0x31, 0x20, 0x35, 0x31, 0x32, 0x20, 0x31, -0x36, 0x20, 0x31, 0x36, 0x20, 0x31, 0x33, 0x0a, 0x2e, 0x72, 0x65, 0x66, -0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x32, 0x34, 0x0a, 0x0a, 0x2e, -0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x33, 0x32, 0x20, 0x20, 0x33, 0x31, -0x20, 0x20, 0x31, 0x20, 0x31, 0x36, 0x20, 0x20, 0x30, 0x0a, 0x2e, 0x74, -0x72, 0x65, 0x65, 0x64, 0x61, 0x74, 0x61, 0x0a, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x38, 0x20, 0x20, 0x30, 0x20, 0x20, -0x34, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, -0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x32, 0x20, 0x20, 0x38, 0x20, 0x20, -0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x63, 0x20, 0x20, 0x30, 0x20, -0x20, 0x61, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x33, 0x20, 0x20, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x36, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x39, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x35, 0x20, 0x20, 0x30, 0x20, 0x20, 0x37, 0x20, 0x0a, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x65, 0x20, 0x20, 0x30, 0x20, 0x20, 0x64, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x66, 0x20, 0x20, 0x30, -0x20, 0x20, 0x62, 0x20, 0x0a, 0x0a, 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, -0x20, 0x33, 0x33, 0x20, 0x20, 0x33, 0x31, 0x20, 0x20, 0x31, 0x20, 0x31, -0x36, 0x20, 0x20, 0x30, 0x0a, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x64, 0x61, -0x74, 0x61, 0x0a, 0x31, 0x30, 0x20, 0x20, 0x31, 0x20, 0x20, 0x38, 0x20, -0x20, 0x31, 0x20, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, -0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, 0x20, 0x30, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x32, 0x20, 0x20, 0x30, 0x20, 0x20, 0x33, 0x20, 0x20, 0x34, 0x20, -0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, -0x20, 0x34, 0x20, 0x0a, 0x20, 0x30, 0x20, 0x20, 0x35, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x36, 0x20, 0x20, 0x30, -0x20, 0x20, 0x37, 0x20, 0x20, 0x38, 0x20, 0x20, 0x31, 0x20, 0x20, 0x34, -0x20, 0x20, 0x31, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, -0x20, 0x20, 0x38, 0x20, 0x20, 0x30, 0x20, 0x20, 0x39, 0x20, 0x20, 0x32, -0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x61, 0x20, 0x20, 0x30, -0x20, 0x20, 0x62, 0x20, 0x0a, 0x20, 0x34, 0x20, 0x20, 0x31, 0x20, 0x20, -0x32, 0x20, 0x20, 0x31, 0x20, 0x20, 0x30, 0x20, 0x20, 0x63, 0x20, 0x20, -0x30, 0x20, 0x20, 0x64, 0x20, 0x20, 0x32, 0x20, 0x20, 0x31, 0x20, 0x20, -0x30, 0x20, 0x20, 0x65, 0x20, 0x20, 0x30, 0x20, 0x20, 0x66, 0x20, 0x0a, -0x0a, 0x2e, 0x65, 0x6e, 0x64, 0x0a -}; diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3StreamState.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3StreamState.cpp deleted file mode 100644 index c7789db42ba..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3StreamState.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A class encapsulating the state of a MP3 stream -// Implementation - -#include "MP3StreamState.hh" -#include "GroupsockHelper.hh" - -#if defined(__WIN32__) || defined(_WIN32) -#define snprintf _snprintf -#endif - -#define MILLION 1000000 - -MP3StreamState::MP3StreamState(UsageEnvironment& env) - : fEnv(env), fFid(NULL), fPresentationTimeScale(1) { -} - -MP3StreamState::~MP3StreamState() { - // Close our open file or socket: - if (fFid != NULL && fFid != stdin) { - if (fFidIsReallyASocket) { - long fid_long = (long)fFid; - closeSocket((int)fid_long); - } else { - fclose(fFid); - } - } -} - -void MP3StreamState::assignStream(FILE* fid, unsigned fileSize) { - fFid = fid; - - if (fileSize == (unsigned)(-1)) { /*HACK#####*/ - fFidIsReallyASocket = 1; - fFileSize = 0; - } else { - fFidIsReallyASocket = 0; - fFileSize = fileSize; - } - fNumFramesInFile = 0; // until we know otherwise - fIsVBR = fHasXingTOC = False; // ditto - - // Set the first frame's 'presentation time' to the current wall time: - gettimeofday(&fNextFramePresentationTime, NULL); -} - -struct timeval MP3StreamState::currentFramePlayTime() const { - unsigned const numSamples = 1152; - unsigned const freq = fr().samplingFreq*(1 + fr().isMPEG2); - - // result is numSamples/freq - unsigned const uSeconds - = ((numSamples*2*MILLION)/freq + 1)/2; // rounds to nearest integer - - struct timeval result; - result.tv_sec = uSeconds/MILLION; - result.tv_usec = uSeconds%MILLION; - return result; -} - -float MP3StreamState::filePlayTime() const { - unsigned numFramesInFile = fNumFramesInFile; - if (numFramesInFile == 0) { - // Estimate the number of frames from the file size, and the - // size of the current frame: - numFramesInFile = fFileSize/(4 + fCurrentFrame.frameSize); - } - - struct timeval const pt = currentFramePlayTime(); - return numFramesInFile*(pt.tv_sec + pt.tv_usec/(float)MILLION); -} - -void MP3StreamState::seekWithinFile(float seekNPT) { - if (fFidIsReallyASocket) return; // it's not seekable - - float fileDuration = filePlayTime(); - if (seekNPT < 0.0) { - seekNPT = 0.0; - } else if (seekNPT > fileDuration) { - seekNPT = fileDuration; - } - float seekFraction = seekNPT/fileDuration; - - unsigned seekByteNumber; - if (fHasXingTOC) { - // The file is VBR, with a Xing TOC; use it to determine which byte to seek to: - float percent = seekFraction*100.0f; - unsigned a = (unsigned)percent; - if (a > 99) a = 99; - - unsigned fa = fXingTOC[a]; - unsigned fb; - if (a < 99) { - fb = fXingTOC[a+1]; - } else { - fb = 256; - } - float seekByteFraction = (fa + (fb-fa)*(percent-a))/256.0f; - - seekByteNumber = (unsigned)(seekByteFraction*fFileSize); - } else { - // Normal case: Treat the file as if it's CBR: - seekByteNumber = (unsigned)(seekFraction*fFileSize); - } - - fseek(fFid, seekByteNumber, SEEK_SET); -} - -unsigned MP3StreamState::findNextHeader(struct timeval& presentationTime) { - presentationTime = fNextFramePresentationTime; - - if (!findNextFrame()) return 0; - - // From this frame, figure out the *next* frame's presentation time: - struct timeval framePlayTime = currentFramePlayTime(); - if (fPresentationTimeScale > 1) { - // Scale this value - unsigned secondsRem = framePlayTime.tv_sec % fPresentationTimeScale; - framePlayTime.tv_sec -= secondsRem; - framePlayTime.tv_usec += secondsRem*MILLION; - framePlayTime.tv_sec /= fPresentationTimeScale; - framePlayTime.tv_usec /= fPresentationTimeScale; - } - fNextFramePresentationTime.tv_usec += framePlayTime.tv_usec; - fNextFramePresentationTime.tv_sec - += framePlayTime.tv_sec + fNextFramePresentationTime.tv_usec/MILLION; - fNextFramePresentationTime.tv_usec %= MILLION; - - return fr().hdr; -} - -Boolean MP3StreamState::readFrame(unsigned char* outBuf, unsigned outBufSize, - unsigned& resultFrameSize, - unsigned& resultDurationInMicroseconds) { - /* We assume that "mp3FindNextHeader()" has already been called */ - - resultFrameSize = 4 + fr().frameSize; - - if (outBufSize < resultFrameSize) { -#ifdef DEBUG_ERRORS - fprintf(stderr, "Insufficient buffer size for reading input frame (%d, need %d)\n", - outBufSize, resultFrameSize); -#endif - if (outBufSize < 4) outBufSize = 0; - resultFrameSize = outBufSize; - - return False; - } - - if (resultFrameSize >= 4) { - unsigned& hdr = fr().hdr; - *outBuf++ = (unsigned char)(hdr>>24); - *outBuf++ = (unsigned char)(hdr>>16); - *outBuf++ = (unsigned char)(hdr>>8); - *outBuf++ = (unsigned char)(hdr); - - memmove(outBuf, fr().frameBytes, resultFrameSize-4); - } - - struct timeval const pt = currentFramePlayTime(); - resultDurationInMicroseconds = pt.tv_sec*MILLION + pt.tv_usec; - - return True; -} - -void MP3StreamState::getAttributes(char* buffer, unsigned bufferSize) const { - char const* formatStr - = "bandwidth %d MPEGnumber %d MPEGlayer %d samplingFrequency %d isStereo %d playTime %d isVBR %d"; - unsigned fpt = (unsigned)(filePlayTime() + 0.5); // rounds to nearest integer -#if defined(IRIX) || defined(ALPHA) || defined(_QNX4) || defined(IMN_PIM) || defined(CRIS) - /* snprintf() isn't defined, so just use sprintf() - ugh! */ - sprintf(buffer, formatStr, - fr().bitrate, fr().isMPEG2 ? 2 : 1, fr().layer, fr().samplingFreq, fr().isStereo, - fpt, fIsVBR); -#else - snprintf(buffer, bufferSize, formatStr, - fr().bitrate, fr().isMPEG2 ? 2 : 1, fr().layer, fr().samplingFreq, fr().isStereo, - fpt, fIsVBR); -#endif -} - -void MP3StreamState::writeGetCmd(char const* hostName, - unsigned short portNum, - char const* fileName) { - char* getCmdFmt = "GET %s HTTP/1.1\r\nHost: %s:%d\r\n\r\n"; - - if (fFidIsReallyASocket) { - long fid_long = (long)fFid; - int sock = (int)fid_long; - char writeBuf[100]; -#if defined(IRIX) || defined(ALPHA) || defined(_QNX4) || defined(IMN_PIM) || defined(CRIS) - /* snprintf() isn't defined, so just use sprintf() */ - /* This is a security risk if filename can come from an external user */ - sprintf(writeBuf, getCmdFmt, fileName, hostName, portNum); -#else - snprintf(writeBuf, sizeof writeBuf, getCmdFmt, - fileName, hostName, portNum); -#endif - send(sock, writeBuf, strlen(writeBuf), 0); - } else { - fprintf(fFid, getCmdFmt, fileName, hostName, portNum); - fflush(fFid); - } -} - -// This is crufty old code that needs to be cleaned up ##### -#define HDRCMPMASK 0xfffffd00 - -Boolean MP3StreamState::findNextFrame() { - unsigned char hbuf[8]; - unsigned l; int i; - int attempt = 0; - -#ifdef DEBUGGING_INPUT - /* use this debugging code to generate a copy of the input stream */ - FILE* fout; - unsigned char c; - fout = fopen("testOut", "w"); - while (readFromStream(&c, 1) ==1) { - fwrite(&c, 1, 1, fout); - } - fclose(fout); - exit(0); -#endif - - read_again: - if (readFromStream(hbuf, 4) != 4) return False; - - fr().hdr = ((unsigned long) hbuf[0] << 24) - | ((unsigned long) hbuf[1] << 16) - | ((unsigned long) hbuf[2] << 8) - | (unsigned long) hbuf[3]; - -#ifdef DEBUG_PARSE - fprintf(stderr, "fr().hdr: 0x%08x\n", fr().hdr); -#endif - if (fr().oldHdr != fr().hdr || !fr().oldHdr) { - i = 0; - init_resync: -#ifdef DEBUG_PARSE - fprintf(stderr, "init_resync: fr().hdr: 0x%08x\n", fr().hdr); -#endif - if ( (fr().hdr & 0xffe00000) != 0xffe00000 - || (fr().hdr & 0x00060000) == 0 // undefined 'layer' field - || (fr().hdr & 0x0000F000) == 0 // 'free format' bitrate index - || (fr().hdr & 0x0000F000) == 0x0000F000 // undefined bitrate index - || (fr().hdr & 0x00000C00) == 0x00000C00 // undefined frequency index - || (fr().hdr & 0x00000003) != 0x00000000 // 'emphasis' field unexpectedly set - ) { - /* RSF: Do the following test even if we're not at the - start of the file, in case we have two or more - separate MP3 files cat'ed together: - */ - /* Check for RIFF hdr */ - if (fr().hdr == ('R'<<24)+('I'<<16)+('F'<<8)+'F') { - unsigned char buf[70 /*was: 40*/]; -#ifdef DEBUG_ERRORS - fprintf(stderr,"Skipped RIFF header\n"); -#endif - readFromStream(buf, 66); /* already read 4 */ - goto read_again; - } - /* Check for ID3 hdr */ - if ((fr().hdr&0xFFFFFF00) == ('I'<<24)+('D'<<16)+('3'<<8)) { - unsigned tagSize, bytesToSkip; - unsigned char buf[1000]; - readFromStream(buf, 6); /* already read 4 */ - tagSize = ((buf[2]&0x7F)<<21) + ((buf[3]&0x7F)<<14) + ((buf[4]&0x7F)<<7) + (buf[5]&0x7F); - bytesToSkip = tagSize; - while (bytesToSkip > 0) { - unsigned bytesToRead = sizeof buf; - if (bytesToRead > bytesToSkip) { - bytesToRead = bytesToSkip; - } - readFromStream(buf, bytesToRead); - bytesToSkip -= bytesToRead; - } -#ifdef DEBUG_ERRORS - fprintf(stderr,"Skipped %d-byte ID3 header\n", tagSize); -#endif - goto read_again; - } - /* give up after 20,000 bytes */ - if (i++ < 20000/*4096*//*1024*/) { - memmove (&hbuf[0], &hbuf[1], 3); - if (readFromStream(hbuf+3,1) != 1) { - return False; - } - fr().hdr <<= 8; - fr().hdr |= hbuf[3]; - fr().hdr &= 0xffffffff; -#ifdef DEBUG_PARSE - fprintf(stderr, "calling init_resync %d\n", i); -#endif - goto init_resync; - } -#ifdef DEBUG_ERRORS - fprintf(stderr,"Giving up searching valid MPEG header\n"); -#endif - return False; - -#ifdef DEBUG_ERRORS - fprintf(stderr,"Illegal Audio-MPEG-Header 0x%08lx at offset 0x%lx.\n", - fr().hdr,tell_stream(str)-4); -#endif - /* Read more bytes until we find something that looks - reasonably like a valid header. This is not a - perfect strategy, but it should get us back on the - track within a short time (and hopefully without - too much distortion in the audio output). */ - do { - attempt++; - memmove (&hbuf[0], &hbuf[1], 7); - if (readFromStream(&hbuf[3],1) != 1) { - return False; - } - - /* This is faster than combining fr().hdr from scratch */ - fr().hdr = ((fr().hdr << 8) | hbuf[3]) & 0xffffffff; - - if (!fr().oldHdr) - goto init_resync; /* "considered harmful", eh? */ - - } while ((fr().hdr & HDRCMPMASK) != (fr().oldHdr & HDRCMPMASK) - && (fr().hdr & HDRCMPMASK) != (fr().firstHdr & HDRCMPMASK)); -#ifdef DEBUG_ERRORS - fprintf (stderr, "Skipped %d bytes in input.\n", attempt); -#endif - } - if (!fr().firstHdr) { - fr().firstHdr = fr().hdr; - } - - fr().setParamsFromHeader(); - fr().setBytePointer(fr().frameBytes, fr().frameSize); - - fr().oldHdr = fr().hdr; - - if (fr().isFreeFormat) { -#ifdef DEBUG_ERRORS - fprintf(stderr,"Free format not supported.\n"); -#endif - return False; - } - -#ifdef MP3_ONLY - if (fr().layer != 3) { -#ifdef DEBUG_ERRORS - fprintf(stderr, "MPEG layer %d is not supported!\n", fr().layer); -#endif - return False; - } -#endif - } - - if ((l = readFromStream(fr().frameBytes, fr().frameSize)) - != fr().frameSize) { - if (l == 0) return False; - memset(fr().frameBytes+1, 0, fr().frameSize-1); - } - - return True; -} - -static Boolean socketIsReadable(int socket) { - const unsigned numFds = socket+1; - fd_set rd_set; - FD_ZERO(&rd_set); - FD_SET((unsigned)socket, &rd_set); - struct timeval timeout; - timeout.tv_sec = timeout.tv_usec = 0; - - int result = select(numFds, &rd_set, NULL, NULL, &timeout); - return result != 0; // not > 0, because windows can return -1 for file sockets -} - -static char watchVariable; - -static void checkFunc(void* /*clientData*/) { - watchVariable = ~0; -} - -static void waitUntilSocketIsReadable(UsageEnvironment& env, int socket) { - while (!socketIsReadable(socket)) { - // Delay a short period of time before checking again. - unsigned usecsToDelay = 1000; // 1 ms - env.taskScheduler().scheduleDelayedTask(usecsToDelay, - (TaskFunc*)checkFunc, (void*)NULL); - watchVariable = 0; - env.taskScheduler().doEventLoop(&watchVariable); - // This allows other tasks to run while we're waiting: - } -} - -unsigned MP3StreamState::readFromStream(unsigned char* buf, - unsigned numChars) { - // Hack for doing socket I/O instead of file I/O (e.g., on Windows) - if (fFidIsReallyASocket) { - long fid_long = (long)fFid; - int sock = (int)fid_long; - unsigned totBytesRead = 0; - do { - waitUntilSocketIsReadable(fEnv, sock); - int bytesRead - = recv(sock, &((char*)buf)[totBytesRead], numChars-totBytesRead, 0); - if (bytesRead < 0) return 0; - - totBytesRead += (unsigned)bytesRead; - } while (totBytesRead < numChars); - - return totBytesRead; - } else { - waitUntilSocketIsReadable(fEnv, (int)fileno(fFid)); - return fread(buf, 1, numChars, fFid); - } -} - -#define XING_FRAMES_FLAG 0x0001 -#define XING_BYTES_FLAG 0x0002 -#define XING_TOC_FLAG 0x0004 -#define XING_VBR_SCALE_FLAG 0x0008 - -void MP3StreamState::checkForXingHeader() { - // Look for 'Xing' in the first 4 bytes after the 'side info': - if (fr().frameSize < fr().sideInfoSize) return; - unsigned bytesAvailable = fr().frameSize - fr().sideInfoSize; - unsigned char* p = &(fr().frameBytes[fr().sideInfoSize]); - - if (bytesAvailable < 8) return; - if (p[0] != 'X' || p[1] != 'i' || p[2] != 'n' || p[3] != 'g') return; - - // We found it. - fIsVBR = True; - - u_int32_t flags = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7]; - unsigned i = 8; - bytesAvailable -= 8; - - if (flags&XING_FRAMES_FLAG) { - // The next 4 bytes are the number of frames: - if (bytesAvailable < 4) return; - fNumFramesInFile = (p[i]<<24)|(p[i+1]<<16)|(p[i+2]<<8)|(p[i+3]); - i += 4; bytesAvailable -= 4; - } - - if (flags&XING_BYTES_FLAG) { - // The next 4 bytes is the file size: - if (bytesAvailable < 4) return; - fFileSize = (p[i]<<24)|(p[i+1]<<16)|(p[i+2]<<8)|(p[i+3]); - i += 4; bytesAvailable -= 4; - } - - if (flags&XING_TOC_FLAG) { - // Fill in the Xing 'table of contents': - if (bytesAvailable < XING_TOC_LENGTH) return; - fHasXingTOC = True; - for (unsigned j = 0; j < XING_TOC_LENGTH; ++j) { - fXingTOC[j] = p[i+j]; - } - i += XING_TOC_FLAG; bytesAvailable -= XING_TOC_FLAG; - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3StreamState.hh b/mythtv/libs/libmythlivemedia/liveMedia/MP3StreamState.hh deleted file mode 100644 index ed3c86b06ee..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3StreamState.hh +++ /dev/null @@ -1,91 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A class encapsulating the state of a MP3 stream -// C++ header - -#ifndef _MP3_STREAM_STATE_HH -#define _MP3_STREAM_STATE_HH - -#ifndef _USAGE_ENVIRONMENT_HH -#include "UsageEnvironment.hh" -#endif -#ifndef _BOOLEAN_HH -#include "Boolean.hh" -#endif -#ifndef _MP3_INTERNALS_HH -#include "MP3Internals.hh" -#endif -#ifndef _NET_COMMON_H -#include "NetCommon.h" -#endif - -#include - -#define XING_TOC_LENGTH 100 - -class MP3StreamState { -public: - MP3StreamState(UsageEnvironment& env); - virtual ~MP3StreamState(); - - void assignStream(FILE* fid, unsigned fileSize); - - unsigned findNextHeader(struct timeval& presentationTime); - Boolean readFrame(unsigned char* outBuf, unsigned outBufSize, - unsigned& resultFrameSize, - unsigned& resultDurationInMicroseconds); - // called after findNextHeader() - - void getAttributes(char* buffer, unsigned bufferSize) const; - - void writeGetCmd(char const* hostName, unsigned short portNum, - char const* fileName); - - float filePlayTime() const; // in seconds - void setPresentationTimeScale(unsigned scale) { fPresentationTimeScale = scale; } - void seekWithinFile(float seekNPT); - - void checkForXingHeader(); // hack for Xing VBR files - -protected: // private->protected requested by Pierre l'Hussiez - unsigned readFromStream(unsigned char* buf, unsigned numChars); - -private: - MP3FrameParams& fr() {return fCurrentFrame;} - MP3FrameParams const& fr() const {return fCurrentFrame;} - - struct timeval currentFramePlayTime() const; - - Boolean findNextFrame(); - -private: - UsageEnvironment& fEnv; - FILE* fFid; - Boolean fFidIsReallyASocket; - unsigned fFileSize; - unsigned fNumFramesInFile; - unsigned fPresentationTimeScale; - // used if we're streaming at other than the normal rate - Boolean fIsVBR, fHasXingTOC; - u_int8_t fXingTOC[XING_TOC_LENGTH]; // set iff "fHasXingTOC" is True - - MP3FrameParams fCurrentFrame; - struct timeval fNextFramePresentationTime; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MP3Transcoder.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MP3Transcoder.cpp deleted file mode 100644 index 054e7ce19e2..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MP3Transcoder.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 Transcoder -// Implementation - -#include "MP3Transcoder.hh" - -MP3Transcoder::MP3Transcoder(UsageEnvironment& env, - MP3ADUTranscoder* aduTranscoder) - : MP3FromADUSource(env, aduTranscoder, False) { -} - -MP3Transcoder::~MP3Transcoder() { -} - -MP3Transcoder* MP3Transcoder::createNew(UsageEnvironment& env, - unsigned outBitrate /* in kbps */, - FramedSource* inputSource) { - MP3Transcoder* newSource = NULL; - - do { - // Create the intermediate filters that help implement the transcoder: - ADUFromMP3Source* aduFromMP3 - = ADUFromMP3Source::createNew(env, inputSource, False); - // Note: This also checks that "inputSource" is an MP3 source - if (aduFromMP3 == NULL) break; - - MP3ADUTranscoder* aduTranscoder - = MP3ADUTranscoder::createNew(env, outBitrate, aduFromMP3); - if (aduTranscoder == NULL) break; - - // Then create the transcoder itself: - newSource = new MP3Transcoder(env, aduTranscoder); - } while (0); - - return newSource; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioRTPSink.cpp deleted file mode 100644 index 0dd9329f04c..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioRTPSink.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for MPEG audio (RFC 2250) -// Implementation - -#include "MPEG1or2AudioRTPSink.hh" - -MPEG1or2AudioRTPSink::MPEG1or2AudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs) - : AudioRTPSink(env, RTPgs, 14, 90000, "MPA") { -} - -MPEG1or2AudioRTPSink::~MPEG1or2AudioRTPSink() { -} - -MPEG1or2AudioRTPSink* -MPEG1or2AudioRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs) { - return new MPEG1or2AudioRTPSink(env, RTPgs); -} - -void MPEG1or2AudioRTPSink::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - // If this is the 1st frame in the 1st packet, set the RTP 'M' (marker) - // bit (because this is considered the start of a talk spurt): - if (isFirstPacket() && isFirstFrameInPacket()) { - setMarkerBit(); - } - - // If this is the first frame in the packet, set the lower half of the - // audio-specific header (to the "fragmentationOffset"): - if (isFirstFrameInPacket()) { - setSpecialHeaderWord(fragmentationOffset&0xFFFF); - } - - // Important: Also call our base class's doSpecialFrameHandling(), - // to set the packet's timestamp: - MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, - frameStart, numBytesInFrame, - frameTimestamp, - numRemainingBytes); -} - -unsigned MPEG1or2AudioRTPSink::specialHeaderSize() const { - // There's a 4 byte special audio header: - return 4; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioRTPSource.cpp deleted file mode 100644 index f8f6ca74b5e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioRTPSource.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG-1 or MPEG-2 Audio RTP Sources -// Implementation - -#include "MPEG1or2AudioRTPSource.hh" - -MPEG1or2AudioRTPSource* -MPEG1or2AudioRTPSource::createNew(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new MPEG1or2AudioRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -MPEG1or2AudioRTPSource::MPEG1or2AudioRTPSource(UsageEnvironment& env, - Groupsock* rtpGS, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, rtpGS, - rtpPayloadFormat, rtpTimestampFrequency) { -} - -MPEG1or2AudioRTPSource::~MPEG1or2AudioRTPSource() { -} - -Boolean MPEG1or2AudioRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - // There's a 4-byte header indicating fragmentation. - if (packet->dataSize() < 4) return False; - - // Note: This fragmentation header is actually useless to us, because - // it doesn't tell us whether or not this RTP packet *ends* a - // fragmented frame. Thus, we can't use it to properly set - // "fCurrentPacketCompletesFrame". Instead, we assume that even - // a partial audio frame will be usable to clients. - - resultSpecialHeaderSize = 4; - return True; -} - -char const* MPEG1or2AudioRTPSource::MIMEtype() const { - return "audio/MPEG"; -} - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioStreamFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioStreamFramer.cpp deleted file mode 100644 index dcf1ef49761..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2AudioStreamFramer.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an MPEG (1,2) audio elementary stream into frames -// Implementation - -#include "MPEG1or2AudioStreamFramer.hh" -#include "StreamParser.hh" -#include "MP3Internals.hh" -#include - -////////// MPEG1or2AudioStreamParser definition ////////// - -class MPEG1or2AudioStreamParser: public StreamParser { -public: - MPEG1or2AudioStreamParser(MPEG1or2AudioStreamFramer* usingSource, - FramedSource* inputSource); - virtual ~MPEG1or2AudioStreamParser(); - -public: - unsigned parse(unsigned& numTruncatedBytes); - // returns the size of the frame that was acquired, or 0 if none was - - void registerReadInterest(unsigned char* to, unsigned maxSize); - - MP3FrameParams const& currentFrame() const { return fCurrentFrame; } - -private: - unsigned char* fTo; - unsigned fMaxSize; - - // Parameters of the most recently read frame: - MP3FrameParams fCurrentFrame; // also works for layer I or II -}; - - -////////// MPEG1or2AudioStreamFramer implementation ////////// - -MPEG1or2AudioStreamFramer -::MPEG1or2AudioStreamFramer(UsageEnvironment& env, FramedSource* inputSource, - Boolean syncWithInputSource) - : FramedFilter(env, inputSource), - fSyncWithInputSource(syncWithInputSource) { - reset(); - - fParser = new MPEG1or2AudioStreamParser(this, inputSource); -} - -MPEG1or2AudioStreamFramer::~MPEG1or2AudioStreamFramer() { - delete fParser; -} - -MPEG1or2AudioStreamFramer* -MPEG1or2AudioStreamFramer::createNew(UsageEnvironment& env, - FramedSource* inputSource, - Boolean syncWithInputSource) { - // Need to add source type checking here??? ##### - return new MPEG1or2AudioStreamFramer(env, inputSource, syncWithInputSource); -} - -void MPEG1or2AudioStreamFramer::flushInput() { - reset(); - fParser->flushInput(); -} - -void MPEG1or2AudioStreamFramer::reset() { - // Use the current wallclock time as the initial 'presentation time': - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - resetPresentationTime(timeNow); -} - -void MPEG1or2AudioStreamFramer -::resetPresentationTime(struct timeval newPresentationTime) { - fNextFramePresentationTime = newPresentationTime; -} - -void MPEG1or2AudioStreamFramer::doGetNextFrame() { - fParser->registerReadInterest(fTo, fMaxSize); - continueReadProcessing(); -} - -#define MILLION 1000000 - -static unsigned const numSamplesByLayer[4] = {0, 384, 1152, 1152}; - -struct timeval MPEG1or2AudioStreamFramer::currentFramePlayTime() const { - MP3FrameParams const& fr = fParser->currentFrame(); - unsigned const numSamples = numSamplesByLayer[fr.layer]; - - struct timeval result; - unsigned const freq = fr.samplingFreq*(1 + fr.isMPEG2); - if (freq == 0) { - result.tv_sec = 0; - result.tv_usec = 0; - return result; - } - - // result is numSamples/freq - unsigned const uSeconds - = ((numSamples*2*MILLION)/freq + 1)/2; // rounds to nearest integer - - result.tv_sec = uSeconds/MILLION; - result.tv_usec = uSeconds%MILLION; - return result; -} - -void MPEG1or2AudioStreamFramer -::continueReadProcessing(void* clientData, - unsigned char* /*ptr*/, unsigned /*size*/, - struct timeval presentationTime) { - MPEG1or2AudioStreamFramer* framer = (MPEG1or2AudioStreamFramer*)clientData; - if (framer->fSyncWithInputSource) { - framer->resetPresentationTime(presentationTime); - } - framer->continueReadProcessing(); -} - -void MPEG1or2AudioStreamFramer::continueReadProcessing() { - unsigned acquiredFrameSize = fParser->parse(fNumTruncatedBytes); - if (acquiredFrameSize > 0) { - // We were able to acquire a frame from the input. - // It has already been copied to the reader's space. - fFrameSize = acquiredFrameSize; - - // Also set the presentation time, and increment it for next time, - // based on the length of this frame: - fPresentationTime = fNextFramePresentationTime; - struct timeval framePlayTime = currentFramePlayTime(); - fDurationInMicroseconds = framePlayTime.tv_sec*MILLION + framePlayTime.tv_usec; - fNextFramePresentationTime.tv_usec += framePlayTime.tv_usec; - fNextFramePresentationTime.tv_sec - += framePlayTime.tv_sec + fNextFramePresentationTime.tv_usec/MILLION; - fNextFramePresentationTime.tv_usec %= MILLION; - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); - } else { - // We were unable to parse a complete frame from the input, because: - // - we had to read more data from the source stream, or - // - the source stream has ended. - } -} - - -////////// MPEG1or2AudioStreamParser implementation ////////// - -MPEG1or2AudioStreamParser -::MPEG1or2AudioStreamParser(MPEG1or2AudioStreamFramer* usingSource, - FramedSource* inputSource) - : StreamParser(inputSource, FramedSource::handleClosure, usingSource, - &MPEG1or2AudioStreamFramer::continueReadProcessing, usingSource) { -} - -MPEG1or2AudioStreamParser::~MPEG1or2AudioStreamParser() { -} - -void MPEG1or2AudioStreamParser::registerReadInterest(unsigned char* to, - unsigned maxSize) { - fTo = to; - fMaxSize = maxSize; -} - -unsigned MPEG1or2AudioStreamParser::parse(unsigned& numTruncatedBytes) { - try { - saveParserState(); - - // We expect a MPEG audio header (first 11 bits set to 1) at the start: - while (((fCurrentFrame.hdr = test4Bytes())&0xFFE00000) != 0xFFE00000) { - skipBytes(1); - saveParserState(); - } - - fCurrentFrame.setParamsFromHeader(); - - // Copy the frame to the requested destination: - unsigned frameSize = fCurrentFrame.frameSize + 4; // include header - if (frameSize > fMaxSize) { - numTruncatedBytes = frameSize - fMaxSize; - frameSize = fMaxSize; - } else { - numTruncatedBytes = 0; - } - - getBytes(fTo, frameSize); - skipBytes(numTruncatedBytes); - - return frameSize; - } catch (int /*e*/) { -#ifdef DEBUG - fprintf(stderr, "MPEG1or2AudioStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n"); -#endif - return 0; // the parsing got interrupted - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2Demux.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2Demux.cpp deleted file mode 100644 index 5d5dcc4f94a..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2Demux.cpp +++ /dev/null @@ -1,756 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Demultiplexer for a MPEG 1 or 2 Program Stream -// Implementation - -#include "MPEG1or2Demux.hh" -#include "MPEG1or2DemuxedElementaryStream.hh" -#include "StreamParser.hh" -#include - -////////// MPEGProgramStreamParser definition ////////// - -// An enum representing the current state of the parser: -enum MPEGParseState { - PARSING_PACK_HEADER, - PARSING_SYSTEM_HEADER, - PARSING_PES_PACKET -}; - -class MPEGProgramStreamParser: public StreamParser { -public: - MPEGProgramStreamParser(MPEG1or2Demux* usingSource, FramedSource* inputSource); - virtual ~MPEGProgramStreamParser(); - -public: - unsigned char parse(); - // returns the stream id of a stream for which a frame was acquired, - // or 0 if no such frame was acquired. - -private: - void setParseState(MPEGParseState parseState); - - void parsePackHeader(); - void parseSystemHeader(); - unsigned char parsePESPacket(); // returns as does parse() - - Boolean isSpecialStreamId(unsigned char stream_id) const; - // for PES packet header parsing - -private: - MPEG1or2Demux* fUsingSource; - MPEGParseState fCurrentParseState; -}; - - -////////// MPEG1or2Demux::OutputDescriptor::SavedData definition/implementation ////////// - -class MPEG1or2Demux::OutputDescriptor::SavedData { -public: - SavedData(unsigned char* buf, unsigned size) - : next(NULL), data(buf), dataSize(size), numBytesUsed(0) { - } - virtual ~SavedData() { - delete[] data; - delete next; - } - - SavedData* next; - unsigned char* data; - unsigned dataSize, numBytesUsed; -}; - - -////////// MPEG1or2Demux implementation ////////// - -MPEG1or2Demux -::MPEG1or2Demux(UsageEnvironment& env, - FramedSource* inputSource, Boolean reclaimWhenLastESDies) - : Medium(env), - fInputSource(inputSource), fMPEGversion(0), - fNextAudioStreamNumber(0), fNextVideoStreamNumber(0), - fReclaimWhenLastESDies(reclaimWhenLastESDies), fNumOutstandingESs(0), - fNumPendingReads(0), fHaveUndeliveredData(False) { - fParser = new MPEGProgramStreamParser(this, inputSource); - for (unsigned i = 0; i < 256; ++i) { - fOutput[i].savedDataHead = fOutput[i].savedDataTail = NULL; - fOutput[i].isPotentiallyReadable = False; - fOutput[i].isCurrentlyActive = False; - fOutput[i].isCurrentlyAwaitingData = False; - } -} - -MPEG1or2Demux::~MPEG1or2Demux() { - delete fParser; - for (unsigned i = 0; i < 256; ++i) delete fOutput[i].savedDataHead; - Medium::close(fInputSource); -} - -MPEG1or2Demux* MPEG1or2Demux -::createNew(UsageEnvironment& env, - FramedSource* inputSource, Boolean reclaimWhenLastESDies) { - // Need to add source type checking here??? ##### - - return new MPEG1or2Demux(env, inputSource, reclaimWhenLastESDies); -} - -MPEG1or2Demux::SCR::SCR() - : highBit(0), remainingBits(0), extension(0), isValid(False) { -} - -void MPEG1or2Demux -::noteElementaryStreamDeletion(MPEG1or2DemuxedElementaryStream* /*es*/) { - if (--fNumOutstandingESs == 0 && fReclaimWhenLastESDies) { - Medium::close(this); - } -} - -void MPEG1or2Demux::flushInput() { - fParser->flushInput(); -} - -MPEG1or2DemuxedElementaryStream* -MPEG1or2Demux::newElementaryStream(u_int8_t streamIdTag) { - ++fNumOutstandingESs; - fOutput[streamIdTag].isPotentiallyReadable = True; - return new MPEG1or2DemuxedElementaryStream(envir(), streamIdTag, *this); -} - -MPEG1or2DemuxedElementaryStream* MPEG1or2Demux::newAudioStream() { - unsigned char newAudioStreamTag = 0xC0 | (fNextAudioStreamNumber++&~0xE0); - // MPEG audio stream tags are 110x xxxx (binary) - return newElementaryStream(newAudioStreamTag); -} - -MPEG1or2DemuxedElementaryStream* MPEG1or2Demux::newVideoStream() { - unsigned char newVideoStreamTag = 0xE0 | (fNextVideoStreamNumber++&~0xF0); - // MPEG video stream tags are 1110 xxxx (binary) - return newElementaryStream(newVideoStreamTag); -} - -// Appropriate one of the reserved stream id tags to mean: return raw PES packets: -#define RAW_PES 0xFC - -MPEG1or2DemuxedElementaryStream* MPEG1or2Demux::newRawPESStream() { - return newElementaryStream(RAW_PES); -} - -void MPEG1or2Demux::registerReadInterest(u_int8_t streamIdTag, - unsigned char* to, unsigned maxSize, - FramedSource::afterGettingFunc* afterGettingFunc, - void* afterGettingClientData, - FramedSource::onCloseFunc* onCloseFunc, - void* onCloseClientData) { - struct OutputDescriptor& out = fOutput[streamIdTag]; - - // Make sure this stream is not already being read: - if (out.isCurrentlyAwaitingData) { - envir() << "MPEG1or2Demux::registerReadInterest(): attempt to read stream id " - << (void*)streamIdTag << " more than once!\n"; - exit(1); - } - - out.to = to; out.maxSize = maxSize; - out.fAfterGettingFunc = afterGettingFunc; - out.afterGettingClientData = afterGettingClientData; - out.fOnCloseFunc = onCloseFunc; - out.onCloseClientData = onCloseClientData; - out.isCurrentlyActive = True; - out.isCurrentlyAwaitingData = True; - // out.frameSize and out.presentationTime will be set when a frame's read - - ++fNumPendingReads; -} - -Boolean MPEG1or2Demux::useSavedData(u_int8_t streamIdTag, - unsigned char* to, unsigned maxSize, - FramedSource::afterGettingFunc* afterGettingFunc, - void* afterGettingClientData) { - struct OutputDescriptor& out = fOutput[streamIdTag]; - if (out.savedDataHead == NULL) return False; // common case - - unsigned totNumBytesCopied = 0; - while (maxSize > 0 && out.savedDataHead != NULL) { - OutputDescriptor::SavedData& savedData = *(out.savedDataHead); - unsigned char* from = &savedData.data[savedData.numBytesUsed]; - unsigned numBytesToCopy = savedData.dataSize - savedData.numBytesUsed; - if (numBytesToCopy > maxSize) numBytesToCopy = maxSize; - memmove(to, from, numBytesToCopy); - to += numBytesToCopy; - maxSize -= numBytesToCopy; - out.savedDataTotalSize -= numBytesToCopy; - totNumBytesCopied += numBytesToCopy; - savedData.numBytesUsed += numBytesToCopy; - if (savedData.numBytesUsed == savedData.dataSize) { - out.savedDataHead = savedData.next; - if (out.savedDataHead == NULL) out.savedDataTail = NULL; - savedData.next = NULL; - delete &savedData; - } - } - - out.isCurrentlyActive = True; - if (afterGettingFunc != NULL) { - struct timeval presentationTime; - presentationTime.tv_sec = 0; presentationTime.tv_usec = 0; // should fix ##### - (*afterGettingFunc)(afterGettingClientData, totNumBytesCopied, - 0 /* numTruncatedBytes */, presentationTime, - 0 /* durationInMicroseconds ?????#####*/); - } - return True; -} - -void MPEG1or2Demux -::continueReadProcessing(void* clientData, - unsigned char* /*ptr*/, unsigned /*size*/, - struct timeval /*presentationTime*/) { - MPEG1or2Demux* demux = (MPEG1or2Demux*)clientData; - demux->continueReadProcessing(); -} - -void MPEG1or2Demux::continueReadProcessing() { - while (fNumPendingReads > 0) { - unsigned char acquiredStreamIdTag = fParser->parse(); - - if (acquiredStreamIdTag != 0) { - // We were able to acquire a frame from the input. - struct OutputDescriptor& newOut = fOutput[acquiredStreamIdTag]; - newOut.isCurrentlyAwaitingData = False; - // indicates that we can be read again - // (This needs to be set before the 'after getting' call below, - // in case it tries to read another frame) - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - if (newOut.fAfterGettingFunc != NULL) { - (*newOut.fAfterGettingFunc)(newOut.afterGettingClientData, - newOut.frameSize, 0 /* numTruncatedBytes */, - newOut.presentationTime, - 0 /* durationInMicroseconds ?????#####*/); - --fNumPendingReads; - } - } else { - // We were unable to parse a complete frame from the input, because: - // - we had to read more data from the source stream, or - // - we found a frame for a stream that was being read, but whose - // reader is not ready to get the frame right now, or - // - the source stream has ended. - break; - } - } -} - -void MPEG1or2Demux::getNextFrame(u_int8_t streamIdTag, - unsigned char* to, unsigned maxSize, - FramedSource::afterGettingFunc* afterGettingFunc, - void* afterGettingClientData, - FramedSource::onCloseFunc* onCloseFunc, - void* onCloseClientData) { - // First, check whether we have saved data for this stream id: - if (useSavedData(streamIdTag, to, maxSize, - afterGettingFunc, afterGettingClientData)) { - return; - } - - // Then save the parameters of the specified stream id: - registerReadInterest(streamIdTag, to, maxSize, - afterGettingFunc, afterGettingClientData, - onCloseFunc, onCloseClientData); - - // Next, if we're the only currently pending read, continue looking for data: - if (fNumPendingReads == 1 || fHaveUndeliveredData) { - fHaveUndeliveredData = 0; - continueReadProcessing(); - } // otherwise the continued read processing has already been taken care of -} - -void MPEG1or2Demux::stopGettingFrames(u_int8_t streamIdTag) { - struct OutputDescriptor& out = fOutput[streamIdTag]; - out.isCurrentlyActive = out.isCurrentlyAwaitingData = False; -} - -void MPEG1or2Demux::handleClosure(void* clientData) { - MPEG1or2Demux* demux = (MPEG1or2Demux*)clientData; - - demux->fNumPendingReads = 0; - - // Tell all pending readers that our source has closed. - // Note that we need to make a copy of our readers' close functions - // (etc.) before we start calling any of them, in case one of them - // ends up deleting this. - struct { - FramedSource::onCloseFunc* fOnCloseFunc; - void* onCloseClientData; - } savedPending[256]; - unsigned i, numPending = 0; - for (i = 0; i < 256; ++i) { - struct OutputDescriptor& out = demux->fOutput[i]; - if (out.isCurrentlyAwaitingData) { - if (out.fOnCloseFunc != NULL) { - savedPending[numPending].fOnCloseFunc = out.fOnCloseFunc; - savedPending[numPending].onCloseClientData = out.onCloseClientData; - ++numPending; - } - } - delete out.savedDataHead; out.savedDataHead = out.savedDataTail = NULL; - out.savedDataTotalSize = 0; - out.isPotentiallyReadable = out.isCurrentlyActive = out.isCurrentlyAwaitingData - = False; - } - for (i = 0; i < numPending; ++i) { - (*savedPending[i].fOnCloseFunc)(savedPending[i].onCloseClientData); - } -} - - -////////// MPEGProgramStreamParser implementation ////////// - -#include - -MPEGProgramStreamParser::MPEGProgramStreamParser(MPEG1or2Demux* usingSource, - FramedSource* inputSource) - : StreamParser(inputSource, MPEG1or2Demux::handleClosure, usingSource, - &MPEG1or2Demux::continueReadProcessing, usingSource), - fUsingSource(usingSource), fCurrentParseState(PARSING_PACK_HEADER) { -} - -MPEGProgramStreamParser::~MPEGProgramStreamParser() { -} - -void MPEGProgramStreamParser::setParseState(MPEGParseState parseState) { - fCurrentParseState = parseState; - saveParserState(); -} - -unsigned char MPEGProgramStreamParser::parse() { - unsigned char acquiredStreamTagId = 0; - - try { - do { - switch (fCurrentParseState) { - case PARSING_PACK_HEADER: { - parsePackHeader(); - break; - } - case PARSING_SYSTEM_HEADER: { - parseSystemHeader(); - break; - } - case PARSING_PES_PACKET: { - acquiredStreamTagId = parsePESPacket(); - break; - } - } - } while(acquiredStreamTagId == 0); - - return acquiredStreamTagId; - } catch (int /*e*/) { -#ifdef DEBUG - fprintf(stderr, "MPEGProgramStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n"); - fflush(stderr); -#endif - return 0; // the parsing got interrupted - } -} - -#define PACK_START_CODE 0x000001BA -#define SYSTEM_HEADER_START_CODE 0x000001BB -#define PACKET_START_CODE_PREFIX 0x00000100 - -static inline Boolean isPacketStartCode(unsigned code) { - return (code&0xFFFFFF00) == PACKET_START_CODE_PREFIX - && code > SYSTEM_HEADER_START_CODE; -} - -void MPEGProgramStreamParser::parsePackHeader() { -#ifdef DEBUG - fprintf(stderr, "parsing pack header\n"); fflush(stderr); -#endif - unsigned first4Bytes; - while (1) { - first4Bytes = test4Bytes(); - - // We're supposed to have a pack header here, but check also for - // a system header or a PES packet, just in case: - if (first4Bytes == PACK_START_CODE) { - skipBytes(4); - break; - } else if (first4Bytes == SYSTEM_HEADER_START_CODE) { -#ifdef DEBUG - fprintf(stderr, "found system header instead of pack header\n"); -#endif - setParseState(PARSING_SYSTEM_HEADER); - return; - } else if (isPacketStartCode(first4Bytes)) { -#ifdef DEBUG - fprintf(stderr, "found packet start code 0x%02x instead of pack header\n", first4Bytes); -#endif - setParseState(PARSING_PES_PACKET); - return; - } - - setParseState(PARSING_PACK_HEADER); // ensures we progress over bad data - if ((first4Bytes&0xFF) > 1) { // a system code definitely doesn't start here - skipBytes(4); - } else { - skipBytes(1); - } - } - - // The size of the pack header differs depending on whether it's - // MPEG-1 or MPEG-2. The next byte tells us this: - unsigned char nextByte = get1Byte(); - MPEG1or2Demux::SCR& scr = fUsingSource->fLastSeenSCR; // alias - if ((nextByte&0xF0) == 0x20) { // MPEG-1 - fUsingSource->fMPEGversion = 1; - scr.highBit = (nextByte&0x08)>>3; - scr.remainingBits = (nextByte&0x06)<<29; - unsigned next4Bytes = get4Bytes(); - scr.remainingBits |= (next4Bytes&0xFFFE0000)>>2; - scr.remainingBits |= (next4Bytes&0x0000FFFE)>>1; - scr.extension = 0; - scr.isValid = True; - skipBits(24); - -#if defined(DEBUG_TIMESTAMPS) || defined(DEBUG_SCR_TIMESTAMPS) - fprintf(stderr, "pack hdr system_clock_reference_base: 0x%x", - scr.highBit); - fprintf(stderr, "%08x\n", scr.remainingBits); -#endif - } else if ((nextByte&0xC0) == 0x40) { // MPEG-2 - fUsingSource->fMPEGversion = 2; - scr.highBit = (nextByte&0x20)>>5; - scr.remainingBits = (nextByte&0x18)<<27; - scr.remainingBits |= (nextByte&0x03)<<28; - unsigned next4Bytes = get4Bytes(); - scr.remainingBits |= (next4Bytes&0xFFF80000)>>4; - scr.remainingBits |= (next4Bytes&0x0003FFF8)>>3; - scr.extension = (next4Bytes&0x00000003)<<7; - next4Bytes = get4Bytes(); - scr.extension |= (next4Bytes&0xFE000000)>>25; - scr.isValid = True; - skipBits(5); - -#if defined(DEBUG_TIMESTAMPS) || defined(DEBUG_SCR_TIMESTAMPS) - fprintf(stderr, "pack hdr system_clock_reference_base: 0x%x", - scr.highBit); - fprintf(stderr, "%08x\n", scr.remainingBits); - fprintf(stderr, "pack hdr system_clock_reference_extension: 0x%03x\n", - scr.extension); -#endif - unsigned char pack_stuffing_length = getBits(3); - skipBytes(pack_stuffing_length); - } else { // unknown - fUsingSource->envir() << "StreamParser::parsePack() saw strange byte " - << (void*)nextByte - << " following pack_start_code\n"; - } - - // Check for a System Header next: - setParseState(PARSING_SYSTEM_HEADER); -} - -void MPEGProgramStreamParser::parseSystemHeader() { -#ifdef DEBUG - fprintf(stderr, "parsing system header\n"); fflush(stderr); -#endif - unsigned next4Bytes = test4Bytes(); - if (next4Bytes != SYSTEM_HEADER_START_CODE) { - // The system header was optional. Look for a PES Packet instead: - setParseState(PARSING_PES_PACKET); - return; - } - -#ifdef DEBUG - fprintf(stderr, "saw system_header_start_code\n"); fflush(stderr); -#endif - skipBytes(4); // we've already seen the system_header_start_code - - unsigned short remaining_header_length = get2Bytes(); - - // According to the MPEG-1 and MPEG-2 specs, "remaining_header_length" should be - // at least 6 bytes. Check this now: - if (remaining_header_length < 6) { - fUsingSource->envir() << "StreamParser::parseSystemHeader(): saw strange header_length: " - << remaining_header_length << " < 6\n"; - } - skipBytes(remaining_header_length); - - // Check for a PES Packet next: - setParseState(PARSING_PES_PACKET); -} - -#define private_stream_1 0xBD -#define private_stream_2 0xBF - -// A test for stream ids that are exempt from normal PES packet header parsing -Boolean MPEGProgramStreamParser -::isSpecialStreamId(unsigned char stream_id) const { - if (stream_id == RAW_PES) return True; // hack - - if (fUsingSource->fMPEGversion == 1) { - return stream_id == private_stream_2; - } else { // assume MPEG-2 - if (stream_id <= private_stream_2) { - return stream_id != private_stream_1; - } else if ((stream_id&0xF0) == 0xF0) { - unsigned char lower4Bits = stream_id&0x0F; - return lower4Bits <= 2 || lower4Bits == 0x8 || lower4Bits == 0xF; - } else { - return False; - } - } -} - -#define READER_NOT_READY 2 - -unsigned char MPEGProgramStreamParser::parsePESPacket() { -#ifdef DEBUG - fprintf(stderr, "parsing PES packet\n"); fflush(stderr); -#endif - unsigned next4Bytes = test4Bytes(); - if (!isPacketStartCode(next4Bytes)) { - // The PES Packet was optional. Look for a Pack Header instead: - setParseState(PARSING_PACK_HEADER); - return 0; - } - -#ifdef DEBUG - fprintf(stderr, "saw packet_start_code_prefix\n"); fflush(stderr); -#endif - skipBytes(3); // we've already seen the packet_start_code_prefix - - unsigned char stream_id = get1Byte(); -#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS) - unsigned char streamNum = stream_id; - char* streamTypeStr; - if ((stream_id&0xE0) == 0xC0) { - streamTypeStr = "audio"; - streamNum = stream_id&~0xE0; - } else if ((stream_id&0xF0) == 0xE0) { - streamTypeStr = "video"; - streamNum = stream_id&~0xF0; - } else if (stream_id == 0xbc) { - streamTypeStr = "reserved"; - } else if (stream_id == 0xbd) { - streamTypeStr = "private_1"; - } else if (stream_id == 0xbe) { - streamTypeStr = "padding"; - } else if (stream_id == 0xbf) { - streamTypeStr = "private_2"; - } else { - streamTypeStr = "unknown"; - } -#endif -#ifdef DEBUG - static unsigned frameCount = 1; - fprintf(stderr, "%d, saw %s stream: 0x%02x\n", frameCount, streamTypeStr, streamNum); fflush(stderr); -#endif - - unsigned short PES_packet_length = get2Bytes(); -#ifdef DEBUG - fprintf(stderr, "PES_packet_length: %d\n", PES_packet_length); fflush(stderr); -#endif - - // Parse over the rest of the header, until we get to the packet data itself. - // This varies depending upon the MPEG version: - if (fUsingSource->fOutput[RAW_PES].isPotentiallyReadable) { - // Hack: We've been asked to return raw PES packets, for every stream: - stream_id = RAW_PES; - } - unsigned savedParserOffset = curOffset(); -#ifdef DEBUG_TIMESTAMPS - unsigned char pts_highBit = 0; - unsigned pts_remainingBits = 0; - unsigned char dts_highBit = 0; - unsigned dts_remainingBits = 0; -#endif - if (fUsingSource->fMPEGversion == 1) { - if (!isSpecialStreamId(stream_id)) { - unsigned char nextByte; - while ((nextByte = get1Byte()) == 0xFF) { // stuffing_byte - } - if ((nextByte&0xC0) == 0x40) { // '01' - skipBytes(1); - nextByte = get1Byte(); - } - if ((nextByte&0xF0) == 0x20) { // '0010' -#ifdef DEBUG_TIMESTAMPS - pts_highBit = (nextByte&0x08)>>3; - pts_remainingBits = (nextByte&0x06)<<29; - unsigned next4Bytes = get4Bytes(); - pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; - pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; -#else - skipBytes(4); -#endif - } else if ((nextByte&0xF0) == 0x30) { // '0011' -#ifdef DEBUG_TIMESTAMPS - pts_highBit = (nextByte&0x08)>>3; - pts_remainingBits = (nextByte&0x06)<<29; - unsigned next4Bytes = get4Bytes(); - pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; - pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; - - nextByte = get1Byte(); - dts_highBit = (nextByte&0x08)>>3; - dts_remainingBits = (nextByte&0x06)<<29; - next4Bytes = get4Bytes(); - dts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; - dts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; -#else - skipBytes(9); -#endif - } - } - } else { // assume MPEG-2 - if (!isSpecialStreamId(stream_id)) { - // Fields in the next 3 bytes determine the size of the rest: - unsigned next3Bytes = getBits(24); -#ifdef DEBUG_TIMESTAMPS - unsigned char PTS_DTS_flags = (next3Bytes&0x00C000)>>14; -#endif -#ifdef undef - unsigned char ESCR_flag = (next3Bytes&0x002000)>>13; - unsigned char ES_rate_flag = (next3Bytes&0x001000)>>12; - unsigned char DSM_trick_mode_flag = (next3Bytes&0x000800)>>11; -#endif - unsigned char PES_header_data_length = (next3Bytes&0x0000FF); -#ifdef DEBUG - fprintf(stderr, "PES_header_data_length: 0x%02x\n", PES_header_data_length); fflush(stderr); -#endif -#ifdef DEBUG_TIMESTAMPS - if (PTS_DTS_flags == 0x2 && PES_header_data_length >= 5) { - unsigned char nextByte = get1Byte(); - pts_highBit = (nextByte&0x08)>>3; - pts_remainingBits = (nextByte&0x06)<<29; - unsigned next4Bytes = get4Bytes(); - pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; - pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; - - skipBytes(PES_header_data_length-5); - } else if (PTS_DTS_flags == 0x3 && PES_header_data_length >= 10) { - unsigned char nextByte = get1Byte(); - pts_highBit = (nextByte&0x08)>>3; - pts_remainingBits = (nextByte&0x06)<<29; - unsigned next4Bytes = get4Bytes(); - pts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; - pts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; - - nextByte = get1Byte(); - dts_highBit = (nextByte&0x08)>>3; - dts_remainingBits = (nextByte&0x06)<<29; - next4Bytes = get4Bytes(); - dts_remainingBits |= (next4Bytes&0xFFFE0000)>>2; - dts_remainingBits |= (next4Bytes&0x0000FFFE)>>1; - - skipBytes(PES_header_data_length-10); - } -#else - skipBytes(PES_header_data_length); -#endif - } - } -#ifdef DEBUG_TIMESTAMPS - fprintf(stderr, "%s stream, ", streamTypeStr); - fprintf(stderr, "packet presentation_time_stamp: 0x%x", pts_highBit); - fprintf(stderr, "%08x\n", pts_remainingBits); - fprintf(stderr, "\t\tpacket decoding_time_stamp: 0x%x", dts_highBit); - fprintf(stderr, "%08x\n", dts_remainingBits); -#endif - - // The rest of the packet will be the "PES_packet_data_byte"s - // Make sure that "PES_packet_length" was consistent with where we are now: - unsigned char acquiredStreamIdTag = 0; - unsigned currentParserOffset = curOffset(); - unsigned bytesSkipped = currentParserOffset - savedParserOffset; - if (stream_id == RAW_PES) { - restoreSavedParserState(); // so we deliver from the beginning of the PES packet - PES_packet_length += 6; // to include the whole of the PES packet - bytesSkipped = 0; - } - if (PES_packet_length < bytesSkipped) { - fUsingSource->envir() << "StreamParser::parsePESPacket(): saw inconsistent PES_packet_length " - << PES_packet_length << " < " - << bytesSkipped << "\n"; - } else { - PES_packet_length -= bytesSkipped; -#ifdef DEBUG - unsigned next4Bytes = test4Bytes(); -#endif - - // Check whether our using source is interested in this stream type. - // If so, deliver the frame to him: - MPEG1or2Demux::OutputDescriptor_t& out = fUsingSource->fOutput[stream_id]; - if (out.isCurrentlyAwaitingData) { - unsigned numBytesToCopy; - if (PES_packet_length > out.maxSize) { - fUsingSource->envir() << "MPEGProgramStreamParser::parsePESPacket() error: PES_packet_length (" - << PES_packet_length - << ") exceeds max frame size asked for (" - << out.maxSize << ")\n"; - numBytesToCopy = out.maxSize; - } else { - numBytesToCopy = PES_packet_length; - } - - getBytes(out.to, numBytesToCopy); - out.frameSize = numBytesToCopy; -#ifdef DEBUG - fprintf(stderr, "%d, %d bytes of PES_packet_data (out.maxSize: %d); first 4 bytes: 0x%08x\n", frameCount, numBytesToCopy, out.maxSize, next4Bytes); fflush(stderr); -#endif - // set out.presentationTime later ##### - acquiredStreamIdTag = stream_id; - PES_packet_length -= numBytesToCopy; - } else if (out.isCurrentlyActive) { - // Someone has been reading this stream, but isn't right now. - // We can't deliver this frame until he asks for it, so punt for now. - // The next time he asks for a frame, he'll get it. -#ifdef DEBUG - fprintf(stderr, "%d, currently undeliverable PES data; first 4 bytes: 0x%08x - currently undeliverable!\n", frameCount, next4Bytes); fflush(stderr); -#endif - restoreSavedParserState(); // so we read from the beginning next time - fUsingSource->fHaveUndeliveredData = True; - throw READER_NOT_READY; - } else if (out.isPotentiallyReadable && - out.savedDataTotalSize + PES_packet_length < 1000000 /*limit*/) { - // Someone is interested in this stream, but hasn't begun reading it yet. - // Save this data, so that the reader will get it when he later asks for it. - unsigned char* buf = new unsigned char[PES_packet_length]; - getBytes(buf, PES_packet_length); - MPEG1or2Demux::OutputDescriptor::SavedData* savedData - = new MPEG1or2Demux::OutputDescriptor::SavedData(buf, PES_packet_length); - if (out.savedDataHead == NULL) { - out.savedDataHead = out.savedDataTail = savedData; - } else { - out.savedDataTail->next = savedData; - out.savedDataTail = savedData; - } - out.savedDataTotalSize += PES_packet_length; - PES_packet_length = 0; - } - skipBytes(PES_packet_length); - } - - // Check for another PES Packet next: - setParseState(PARSING_PES_PACKET); -#ifdef DEBUG - ++frameCount; -#endif - return acquiredStreamIdTag; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2DemuxedElementaryStream.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2DemuxedElementaryStream.cpp deleted file mode 100644 index 0dbc7670c76..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2DemuxedElementaryStream.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A MPEG 1 or 2 Elementary Stream, demultiplexed from a Program Stream -// Implementation - -#include "MPEG1or2DemuxedElementaryStream.hh" - -////////// MPEG1or2DemuxedElementaryStream ////////// - -MPEG1or2DemuxedElementaryStream:: -MPEG1or2DemuxedElementaryStream(UsageEnvironment& env, u_int8_t streamIdTag, - MPEG1or2Demux& sourceDemux) - : FramedSource(env), - fOurStreamIdTag(streamIdTag), fOurSourceDemux(sourceDemux), fMPEGversion(0) { - // Set our MIME type string for known media types: - if ((streamIdTag&0xE0) == 0xC0) { - fMIMEtype = "audio/MPEG"; - } else if ((streamIdTag&0xF0) == 0xE0) { - fMIMEtype = "video/MPEG"; - } else { - fMIMEtype = MediaSource::MIMEtype(); - } -} - -MPEG1or2DemuxedElementaryStream::~MPEG1or2DemuxedElementaryStream() { - fOurSourceDemux.noteElementaryStreamDeletion(this); -} - -void MPEG1or2DemuxedElementaryStream::doGetNextFrame() { - fOurSourceDemux.getNextFrame(fOurStreamIdTag, fTo, fMaxSize, - afterGettingFrame, this, - handleClosure, this); -} - -void MPEG1or2DemuxedElementaryStream::doStopGettingFrames() { - fOurSourceDemux.stopGettingFrames(fOurStreamIdTag); -} - -char const* MPEG1or2DemuxedElementaryStream::MIMEtype() const { - return fMIMEtype; -} - -unsigned MPEG1or2DemuxedElementaryStream::maxFrameSize() const { - return 6+65535; - // because the MPEG spec allows for PES packets as large as - // (6 + 65535) bytes (header + data) -} - -void MPEG1or2DemuxedElementaryStream -::afterGettingFrame(void* clientData, - unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - MPEG1or2DemuxedElementaryStream* stream - = (MPEG1or2DemuxedElementaryStream*)clientData; - stream->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -void MPEG1or2DemuxedElementaryStream -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - fFrameSize = frameSize; - fNumTruncatedBytes = numTruncatedBytes; - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - - fLastSeenSCR = fOurSourceDemux.lastSeenSCR(); - fMPEGversion = fOurSourceDemux.mpegVersion(); - - FramedSource::afterGetting(this); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2DemuxedServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2DemuxedServerMediaSubsession.cpp deleted file mode 100644 index fdd25e7dfec..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2DemuxedServerMediaSubsession.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-1 or 2 demuxer. -// Implementation - -#include "MPEG1or2DemuxedServerMediaSubsession.hh" -#include "MPEG1or2AudioStreamFramer.hh" -#include "MPEG1or2AudioRTPSink.hh" -#include "MPEG1or2VideoStreamFramer.hh" -#include "MPEG1or2VideoRTPSink.hh" -#include "AC3AudioStreamFramer.hh" -#include "AC3AudioRTPSink.hh" -#include "ByteStreamFileSource.hh" - -MPEG1or2DemuxedServerMediaSubsession* MPEG1or2DemuxedServerMediaSubsession -::createNew(MPEG1or2FileServerDemux& demux, u_int8_t streamIdTag, - Boolean reuseFirstSource, Boolean iFramesOnly, double vshPeriod) { - return new MPEG1or2DemuxedServerMediaSubsession(demux, streamIdTag, - reuseFirstSource, - iFramesOnly, vshPeriod); -} - -MPEG1or2DemuxedServerMediaSubsession -::MPEG1or2DemuxedServerMediaSubsession(MPEG1or2FileServerDemux& demux, - u_int8_t streamIdTag, Boolean reuseFirstSource, - Boolean iFramesOnly, double vshPeriod) - : OnDemandServerMediaSubsession(demux.envir(), reuseFirstSource), - fOurDemux(demux), fStreamIdTag(streamIdTag), - fIFramesOnly(iFramesOnly), fVSHPeriod(vshPeriod) { -} - -MPEG1or2DemuxedServerMediaSubsession::~MPEG1or2DemuxedServerMediaSubsession() { -} - -FramedSource* MPEG1or2DemuxedServerMediaSubsession -::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate) { - FramedSource* es = NULL; - do { - es = fOurDemux.newElementaryStream(clientSessionId, fStreamIdTag); - if (es == NULL) break; - - if ((fStreamIdTag&0xF0) == 0xC0 /*MPEG audio*/) { - estBitrate = 128; // kbps, estimate - return MPEG1or2AudioStreamFramer::createNew(envir(), es); - } else if ((fStreamIdTag&0xF0) == 0xE0 /*video*/) { - estBitrate = 500; // kbps, estimate - return MPEG1or2VideoStreamFramer::createNew(envir(), es, - fIFramesOnly, fVSHPeriod); - } else if (fStreamIdTag == 0xBD /*AC-3 audio*/) { - estBitrate = 192; // kbps, estimate - return AC3AudioStreamFramer::createNew(envir(), es); - } else { // unknown stream type - break; - } - } while (0); - - // An error occurred: - Medium::close(es); - return NULL; -} - -RTPSink* MPEG1or2DemuxedServerMediaSubsession -::createNewRTPSink(Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource) { - if ((fStreamIdTag&0xF0) == 0xC0 /*MPEG audio*/) { - return MPEG1or2AudioRTPSink::createNew(envir(), rtpGroupsock); - } else if ((fStreamIdTag&0xF0) == 0xE0 /*video*/) { - return MPEG1or2VideoRTPSink::createNew(envir(), rtpGroupsock); - } else if (fStreamIdTag == 0xBD /*AC-3 audio*/) { - // Get the sampling frequency from the audio source; use it for the RTP frequency: - AC3AudioStreamFramer* audioSource - = (AC3AudioStreamFramer*)inputSource; - return AC3AudioRTPSink::createNew(envir(), rtpGroupsock, rtpPayloadTypeIfDynamic, - audioSource->samplingRate()); - } else { - return NULL; - } -} - -void MPEG1or2DemuxedServerMediaSubsession -::seekStreamSource(FramedSource* inputSource, float seekNPT) { - float const dur = duration(); - unsigned const size = fOurDemux.fileSize(); - unsigned absBytePosition = dur == 0.0 ? 0 : (unsigned)((seekNPT/dur)*size); - - // "inputSource" is a 'framer' - // Flush its data, to account for the seek that we're about to do: - if ((fStreamIdTag&0xF0) == 0xC0 /*MPEG audio*/) { - MPEG1or2AudioStreamFramer* framer = (MPEG1or2AudioStreamFramer*)inputSource; - framer->flushInput(); - } else if ((fStreamIdTag&0xF0) == 0xE0 /*video*/) { - MPEG1or2VideoStreamFramer* framer = (MPEG1or2VideoStreamFramer*)inputSource; - framer->flushInput(); - } - - // "inputSource" is a filter; its input source is the original elem stream source: - MPEG1or2DemuxedElementaryStream* elemStreamSource - = (MPEG1or2DemuxedElementaryStream*)(((FramedFilter*)inputSource)->inputSource()); - - // Next, get the original source demux: - MPEG1or2Demux& sourceDemux = elemStreamSource->sourceDemux(); - - // and flush its input buffers: - sourceDemux.flushInput(); - - // Then, get the original input file stream from the source demux: - ByteStreamFileSource* inputFileSource - = (ByteStreamFileSource*)(sourceDemux.inputSource()); - // Note: We can make that cast, because we know that the demux was originally - // created from a "ByteStreamFileSource". - - // Do the appropriate seek within the input file stream: - inputFileSource->seekToByteAbsolute(absBytePosition); -} - -float MPEG1or2DemuxedServerMediaSubsession::duration() const { - return fOurDemux.fileDuration(); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2FileServerDemux.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2FileServerDemux.cpp deleted file mode 100644 index cd43edd8d99..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2FileServerDemux.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A server demultiplexer for a MPEG 1 or 2 Program Stream -// Implementation - -#include "MPEG1or2FileServerDemux.hh" -#include "MPEG1or2DemuxedServerMediaSubsession.hh" -#include "ByteStreamFileSource.hh" - -MPEG1or2FileServerDemux* -MPEG1or2FileServerDemux::createNew(UsageEnvironment& env, char const* fileName, - Boolean reuseFirstSource) { - return new MPEG1or2FileServerDemux(env, fileName, reuseFirstSource); -} - -static float MPEG1or2ProgramStreamFileDuration(UsageEnvironment& env, - char const* fileName, - unsigned& fileSize); // forward -MPEG1or2FileServerDemux -::MPEG1or2FileServerDemux(UsageEnvironment& env, char const* fileName, - Boolean reuseFirstSource) - : Medium(env), - fReuseFirstSource(reuseFirstSource), - fSession0Demux(NULL), fLastCreatedDemux(NULL), fLastClientSessionId(~0) { - fFileName = strDup(fileName); - fFileDuration = MPEG1or2ProgramStreamFileDuration(env, fileName, fFileSize); -} - -MPEG1or2FileServerDemux::~MPEG1or2FileServerDemux() { - Medium::close(fSession0Demux); - delete[] (char*)fFileName; -} - -ServerMediaSubsession* -MPEG1or2FileServerDemux::newAudioServerMediaSubsession() { - return MPEG1or2DemuxedServerMediaSubsession::createNew(*this, 0xC0, fReuseFirstSource); -} - -ServerMediaSubsession* -MPEG1or2FileServerDemux::newVideoServerMediaSubsession(Boolean iFramesOnly, - double vshPeriod) { - return MPEG1or2DemuxedServerMediaSubsession::createNew(*this, 0xE0, fReuseFirstSource, - iFramesOnly, vshPeriod); -} - -ServerMediaSubsession* -MPEG1or2FileServerDemux::newAC3AudioServerMediaSubsession() { - return MPEG1or2DemuxedServerMediaSubsession::createNew(*this, 0xBD, fReuseFirstSource); - // because, in a VOB file, the AC3 audio has stream id 0xBD -} - -MPEG1or2DemuxedElementaryStream* -MPEG1or2FileServerDemux::newElementaryStream(unsigned clientSessionId, - u_int8_t streamIdTag) { - MPEG1or2Demux* demuxToUse; - if (clientSessionId == 0) { - // 'Session 0' is treated especially, because its audio & video streams - // are created and destroyed one-at-a-time, rather than both streams being - // created, and then (later) both streams being destroyed (as is the case - // for other ('real') session ids). Because of this, a separate demux is - // used for session 0, and its deletion is managed by us, rather than - // happening automatically. - if (fSession0Demux == NULL) { - // Open our input file as a 'byte-stream file source': - ByteStreamFileSource* fileSource - = ByteStreamFileSource::createNew(envir(), fFileName); - if (fileSource == NULL) return NULL; - fSession0Demux = MPEG1or2Demux::createNew(envir(), fileSource, False/*note!*/); - } - demuxToUse = fSession0Demux; - } else { - // First, check whether this is a new client session. If so, create a new - // demux for it: - if (clientSessionId != fLastClientSessionId) { - // Open our input file as a 'byte-stream file source': - ByteStreamFileSource* fileSource - = ByteStreamFileSource::createNew(envir(), fFileName); - if (fileSource == NULL) return NULL; - - fLastCreatedDemux = MPEG1or2Demux::createNew(envir(), fileSource, True); - // Note: We tell the demux to delete itself when its last - // elementary stream is deleted. - fLastClientSessionId = clientSessionId; - // Note: This code relies upon the fact that the creation of streams for - // different client sessions do not overlap - so one "MPEG1or2Demux" is used - // at a time. - } - demuxToUse = fLastCreatedDemux; - } - - if (demuxToUse == NULL) return NULL; // shouldn't happen - - return demuxToUse->newElementaryStream(streamIdTag); -} - - -static Boolean getMPEG1or2TimeCode(FramedSource* dataSource, - MPEG1or2Demux& parentDemux, - Boolean returnFirstSeenCode, - float& timeCode); // forward - -static float MPEG1or2ProgramStreamFileDuration(UsageEnvironment& env, - char const* fileName, - unsigned& fileSize) { - FramedSource* dataSource = NULL; - float duration = 0.0; // until we learn otherwise - fileSize = 0; // ditto - - do { - // Open the input file as a 'byte-stream file source': - ByteStreamFileSource* fileSource = ByteStreamFileSource::createNew(env, fileName); - if (fileSource == NULL) break; - dataSource = fileSource; - - fileSize = (unsigned)(fileSource->fileSize()); - if (fileSize == 0) break; - - // Create a MPEG demultiplexor that reads from that source. - MPEG1or2Demux* baseDemux = MPEG1or2Demux::createNew(env, dataSource, True); - if (baseDemux == NULL) break; - - // Create, from this, a source that returns raw PES packets: - dataSource = baseDemux->newRawPESStream(); - - // Read the first time code from the file: - float firstTimeCode; - if (!getMPEG1or2TimeCode(dataSource, *baseDemux, True, firstTimeCode)) break; - - // Then, read the last time code from the file. - // (Before doing this, flush the demux's input buffers, - // and seek towards the end of the file, for efficiency.) - baseDemux->flushInput(); - unsigned const startByteFromEnd = 100000; - unsigned newFilePosition - = fileSize < startByteFromEnd ? 0 : fileSize - startByteFromEnd; - if (newFilePosition > 0) fileSource->seekToByteAbsolute(newFilePosition); - - float lastTimeCode; - if (!getMPEG1or2TimeCode(dataSource, *baseDemux, False, lastTimeCode)) break; - - // Take the difference between these time codes as being the file duration: - float timeCodeDiff = lastTimeCode - firstTimeCode; - if (timeCodeDiff < 0) break; - duration = timeCodeDiff; - } while (0); - - Medium::close(dataSource); - return duration; -} - -class DummySink: public MediaSink { -public: - DummySink(MPEG1or2Demux& demux, Boolean returnFirstSeenCode); - virtual ~DummySink(); - - char watchVariable; - -private: - // redefined virtual function: - virtual Boolean continuePlaying(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(); - -private: - MPEG1or2Demux& fOurDemux; - Boolean fReturnFirstSeenCode; - unsigned char fBuf[10000]; -}; - -static void afterPlayingDummySink(DummySink* sink); // forward -static float computeSCRTimeCode(MPEG1or2Demux::SCR const& scr); // forward - -static Boolean getMPEG1or2TimeCode(FramedSource* dataSource, - MPEG1or2Demux& parentDemux, - Boolean returnFirstSeenCode, - float& timeCode) { - // Start reading through "dataSource", until we see a SCR time code: - parentDemux.lastSeenSCR().isValid = False; - UsageEnvironment& env = dataSource->envir(); // alias - DummySink sink(parentDemux, returnFirstSeenCode); - sink.startPlaying(*dataSource, - (MediaSink::afterPlayingFunc*)afterPlayingDummySink, &sink); - env.taskScheduler().doEventLoop(&sink.watchVariable); - - timeCode = computeSCRTimeCode(parentDemux.lastSeenSCR()); - return parentDemux.lastSeenSCR().isValid; -} - - -////////// DummySink implementation ////////// - -DummySink::DummySink(MPEG1or2Demux& demux, Boolean returnFirstSeenCode) - : MediaSink(demux.envir()), - watchVariable(0), fOurDemux(demux), fReturnFirstSeenCode(returnFirstSeenCode) { -} - -DummySink::~DummySink() { -} - -Boolean DummySink::continuePlaying() { - fSource->getNextFrame(fBuf, sizeof fBuf, - afterGettingFrame, this, - onSourceClosure, this); - return True; -} - -void DummySink::afterGettingFrame(void* clientData, unsigned /*frameSize*/, - unsigned /*numTruncatedBytes*/, - struct timeval /*presentationTime*/, - unsigned /*durationInMicroseconds*/) { - DummySink* sink = (DummySink*)clientData; - sink->afterGettingFrame1(); -} - -void DummySink::afterGettingFrame1() { - if (fReturnFirstSeenCode && fOurDemux.lastSeenSCR().isValid) { - // We were asked to return the first SCR that we saw, and we've seen one, - // so we're done. (Handle this as if the input source had closed.) - onSourceClosure(this); - return; - } - - continuePlaying(); -} - -static void afterPlayingDummySink(DummySink* sink) { - // Return from the "doEventLoop()" call: - sink->watchVariable = ~0; -} - -static float computeSCRTimeCode(MPEG1or2Demux::SCR const& scr) { - double result = scr.remainingBits/90000.0 + scr.extension/300.0; - if (scr.highBit) { - // Add (2^32)/90000 == (2^28)/5625 - double const highBitValue = (256*1024*1024)/5625.0; - result += highBitValue; - } - - return (float)result; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoFileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoFileServerMediaSubsession.cpp deleted file mode 100644 index 861289bae44..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoFileServerMediaSubsession.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-1 or 2 Elementary Stream video file. -// Implementation - -#include "MPEG1or2VideoFileServerMediaSubsession.hh" -#include "MPEG1or2VideoRTPSink.hh" -#include "ByteStreamFileSource.hh" -#include "MPEG1or2VideoStreamFramer.hh" - -MPEG1or2VideoFileServerMediaSubsession* -MPEG1or2VideoFileServerMediaSubsession::createNew(UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource, - Boolean iFramesOnly, - double vshPeriod) { - return new MPEG1or2VideoFileServerMediaSubsession(env, fileName, reuseFirstSource, - iFramesOnly, vshPeriod); -} - -MPEG1or2VideoFileServerMediaSubsession -::MPEG1or2VideoFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource, - Boolean iFramesOnly, - double vshPeriod) - : FileServerMediaSubsession(env, fileName, reuseFirstSource), - fIFramesOnly(iFramesOnly), fVSHPeriod(vshPeriod) { -} - -MPEG1or2VideoFileServerMediaSubsession -::~MPEG1or2VideoFileServerMediaSubsession() { -} - -FramedSource* MPEG1or2VideoFileServerMediaSubsession -::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) { - estBitrate = 500; // kbps, estimate - - ByteStreamFileSource* fileSource - = ByteStreamFileSource::createNew(envir(), fFileName); - if (fileSource == NULL) return NULL; - fFileSize = fileSource->fileSize(); - - return MPEG1or2VideoStreamFramer - ::createNew(envir(), fileSource, fIFramesOnly, fVSHPeriod); -} - -RTPSink* MPEG1or2VideoFileServerMediaSubsession -::createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char /*rtpPayloadTypeIfDynamic*/, - FramedSource* /*inputSource*/) { - return MPEG1or2VideoRTPSink::createNew(envir(), rtpGroupsock); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoHTTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoHTTPSink.cpp deleted file mode 100644 index 053c71368c5..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoHTTPSink.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A HTTP Sink specifically for MPEG Video -// Implementation - -#include "MPEG1or2VideoHTTPSink.hh" - -////////// MPEG1or2VideoHTTPSink ////////// - -MPEG1or2VideoHTTPSink* MPEG1or2VideoHTTPSink::createNew(UsageEnvironment& env, Port ourPort) { - int ourSocket = -1; - - do { - int ourSocket = setUpOurSocket(env, ourPort); - if (ourSocket == -1) break; - - MPEG1or2VideoHTTPSink* newSink = new MPEG1or2VideoHTTPSink(env, ourSocket); - if (newSink == NULL) break; - - appendPortNum(env, ourPort); - - return newSink; - } while (0); - - if (ourSocket != -1) ::closeSocket(ourSocket); - return NULL; -} - -MPEG1or2VideoHTTPSink::MPEG1or2VideoHTTPSink(UsageEnvironment& env, int ourSocket) - : HTTPSink(env, ourSocket), fHaveSeenFirstVSH(False) { -} - -MPEG1or2VideoHTTPSink::~MPEG1or2VideoHTTPSink() { -} - -#define VIDEO_SEQUENCE_HEADER_START_CODE 0x000001B3 - -Boolean MPEG1or2VideoHTTPSink::isUseableFrame(unsigned char* framePtr, - unsigned frameSize) { - // Some clients get confused if the data we give them does not start - // with a 'video_sequence_header', so we ignore any frames that precede - // the first 'video_sequence_header': - - // Sanity check: a frame with < 4 bytes is never valid: - if (frameSize < 4) return False; - - if (fHaveSeenFirstVSH) return True; - - unsigned first4Bytes - = (framePtr[0]<<24)|(framePtr[1]<<16)|(framePtr[2]<<8)|framePtr[3]; - - if (first4Bytes == VIDEO_SEQUENCE_HEADER_START_CODE) { - fHaveSeenFirstVSH = True; - return True; - } else { - return False; - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoRTPSink.cpp deleted file mode 100644 index 8a3d55add3c..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoRTPSink.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for MPEG video (RFC 2250) -// Implementation - -#include "MPEG1or2VideoRTPSink.hh" -#include "MPEG1or2VideoStreamFramer.hh" - -MPEG1or2VideoRTPSink::MPEG1or2VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs) - : VideoRTPSink(env, RTPgs, 32, 90000, "MPV") { - fPictureState.temporal_reference = 0; - fPictureState.picture_coding_type = fPictureState.vector_code_bits = 0; -} - -MPEG1or2VideoRTPSink::~MPEG1or2VideoRTPSink() { -} - -MPEG1or2VideoRTPSink* -MPEG1or2VideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs) { - return new MPEG1or2VideoRTPSink(env, RTPgs); -} - -Boolean MPEG1or2VideoRTPSink::sourceIsCompatibleWithUs(MediaSource& source) { - // Our source must be an appropriate framer: - return source.isMPEG1or2VideoStreamFramer(); -} - -Boolean MPEG1or2VideoRTPSink::allowFragmentationAfterStart() const { - return True; -} - -Boolean MPEG1or2VideoRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const { - // A 'frame' (which in this context can mean a header or a slice as well as a - // complete picture) can appear at other than the first position in a packet - // in all situations, EXCEPT when it follows the end of (i.e., the last slice - // of) a picture. I.e., the headers at the beginning of a picture must - // appear at the start of a RTP packet. - if (!fPreviousFrameWasSlice) return True; - - // A slice is already packed into this packet. We allow this new 'frame' - // to be packed after it, provided that it is also a slice: - return numBytesInFrame >= 4 - && frameStart[0] == 0 && frameStart[1] == 0 && frameStart[2] == 1 - && frameStart[3] >= 1 && frameStart[3] <= 0xAF; -} - -#define VIDEO_SEQUENCE_HEADER_START_CODE 0x000001B3 -#define PICTURE_START_CODE 0x00000100 - -void MPEG1or2VideoRTPSink -::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - Boolean thisFrameIsASlice = False; // until we learn otherwise - if (isFirstFrameInPacket()) { - fSequenceHeaderPresent = fPacketBeginsSlice = fPacketEndsSlice = False; - } - - if (fragmentationOffset == 0) { - // Begin by inspecting the 4-byte code at the start of the frame: - if (numBytesInFrame < 4) return; // shouldn't happen - unsigned startCode = (frameStart[0]<<24) | (frameStart[1]<<16) - | (frameStart[2]<<8) | frameStart[3]; - - if (startCode == VIDEO_SEQUENCE_HEADER_START_CODE) { - // This is a video sequence header - fSequenceHeaderPresent = True; - } else if (startCode == PICTURE_START_CODE) { - // This is a picture header - - // Record the parameters of this picture: - if (numBytesInFrame < 8) return; // shouldn't happen - unsigned next4Bytes = (frameStart[4]<<24) | (frameStart[5]<<16) - | (frameStart[6]<<8) | frameStart[7]; - unsigned char byte8 = numBytesInFrame == 8 ? 0 : frameStart[8]; - - fPictureState.temporal_reference = (next4Bytes&0xFFC00000)>>(32-10); - fPictureState.picture_coding_type = (next4Bytes&0x00380000)>>(32-(10+3)); - - unsigned char FBV, BFC, FFV, FFC; - FBV = BFC = FFV = FFC = 0; - switch (fPictureState.picture_coding_type) { - case 3: - FBV = (byte8&0x40)>>6; - BFC = (byte8&0x38)>>3; - // fall through to: - case 2: - FFV = (next4Bytes&0x00000004)>>2; - FFC = ((next4Bytes&0x00000003)<<1) | ((byte8&0x80)>>7); - } - - fPictureState.vector_code_bits = (FBV<<7) | (BFC<<4) | (FFV<<3) | FFC; - } else if ((startCode&0xFFFFFF00) == 0x00000100) { - unsigned char lastCodeByte = startCode&0xFF; - - if (lastCodeByte <= 0xAF) { - // This is (the start of) a slice - thisFrameIsASlice = True; - } else { - // This is probably a GOP header; we don't do anything with this - } - } else { - // The first 4 bytes aren't a code that we recognize. - envir() << "Warning: MPEG1or2VideoRTPSink::doSpecialFrameHandling saw strange first 4 bytes " - << (void*)startCode << ", but we're not a fragment\n"; - } - } else { - // We're a fragment (other than the first) of a slice. - thisFrameIsASlice = True; - } - - if (thisFrameIsASlice) { - // This packet begins a slice iff there's no fragmentation offset: - fPacketBeginsSlice = (fragmentationOffset == 0); - - // This packet also ends a slice iff there are no fragments remaining: - fPacketEndsSlice = (numRemainingBytes == 0); - } - - // Set the video-specific header based on the parameters that we've seen. - // Note that this may get done more than once, if several frames appear - // in the packet. That's OK, because this situation happens infrequently, - // and we want the video-specific header to reflect the most up-to-date - // information (in particular, from a Picture Header) anyway. - unsigned videoSpecificHeader = - // T == 0 - (fPictureState.temporal_reference<<16) | - // AN == N == 0 - (fSequenceHeaderPresent<<13) | - (fPacketBeginsSlice<<12) | - (fPacketEndsSlice<<11) | - (fPictureState.picture_coding_type<<8) | - fPictureState.vector_code_bits; - setSpecialHeaderWord(videoSpecificHeader); - - // Also set the RTP timestamp. (As above, we do this for each frame - // in the packet.) - setTimestamp(frameTimestamp); - - // Set the RTP 'M' (marker) bit iff this frame ends (i.e., is the last - // slice of) a picture (and there are no fragments remaining). - // This relies on the source being a "MPEG1or2VideoStreamFramer". - MPEG1or2VideoStreamFramer* framerSource = (MPEG1or2VideoStreamFramer*)fSource; - if (framerSource != NULL && framerSource->pictureEndMarker() - && numRemainingBytes == 0) { - setMarkerBit(); - framerSource->pictureEndMarker() = False; - } - - fPreviousFrameWasSlice = thisFrameIsASlice; -} - -unsigned MPEG1or2VideoRTPSink::specialHeaderSize() const { - // There's a 4 byte special audio header: - return 4; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoRTPSource.cpp deleted file mode 100644 index 015d40482a0..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoRTPSource.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG-1 or MPEG-2 Video RTP Sources -// Implementation - -#include "MPEG1or2VideoRTPSource.hh" - -MPEG1or2VideoRTPSource* -MPEG1or2VideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new MPEG1or2VideoRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -MPEG1or2VideoRTPSource::MPEG1or2VideoRTPSource(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency){ -} - -MPEG1or2VideoRTPSource::~MPEG1or2VideoRTPSource() { -} - -Boolean MPEG1or2VideoRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - // There's a 4-byte video-specific header - if (packet->dataSize() < 4) return False; - - u_int32_t header = ntohl(*(unsigned*)(packet->data())); - - u_int32_t sBit = header&0x00002000; // sequence-header-present - u_int32_t bBit = header&0x00001000; // beginning-of-slice - u_int32_t eBit = header&0x00000800; // end-of-slice - - fCurrentPacketBeginsFrame = (sBit|bBit) != 0; - fCurrentPacketCompletesFrame = ((sBit&~bBit)|eBit) != 0; - - resultSpecialHeaderSize = 4; - return True; -} - -Boolean MPEG1or2VideoRTPSource -::packetIsUsableInJitterCalculation(unsigned char* packet, - unsigned packetSize) { - // There's a 4-byte video-specific header - if (packetSize < 4) return False; - - // Extract the "Picture-Type" field from this, to determine whether - // this packet can be used in jitter calculations: - unsigned header = ntohl(*(unsigned*)packet); - - unsigned short pictureType = (header>>8)&0x7; - if (pictureType == 1) { // an I frame - return True; - } else { // a P, B, D, or other unknown frame type - return False; - } -} - -char const* MPEG1or2VideoRTPSource::MIMEtype() const { - return "video/MPEG"; -} - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoStreamDiscreteFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoStreamDiscreteFramer.cpp deleted file mode 100644 index 55aa7d28d5c..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoStreamDiscreteFramer.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simplified version of "MPEG1or2VideoStreamFramer" that takes only -// complete, discrete frames (rather than an arbitrary byte stream) as input. -// This avoids the parsing and data copying overhead of the full -// "MPEG1or2VideoStreamFramer". -// Implementation - -#include "MPEG1or2VideoStreamDiscreteFramer.hh" - -MPEG1or2VideoStreamDiscreteFramer* -MPEG1or2VideoStreamDiscreteFramer::createNew(UsageEnvironment& env, - FramedSource* inputSource, - Boolean iFramesOnly, - double vshPeriod) { - // Need to add source type checking here??? ##### - return new MPEG1or2VideoStreamDiscreteFramer(env, inputSource, - iFramesOnly, vshPeriod); -} - -MPEG1or2VideoStreamDiscreteFramer -::MPEG1or2VideoStreamDiscreteFramer(UsageEnvironment& env, - FramedSource* inputSource, - Boolean iFramesOnly, double vshPeriod) - : MPEG1or2VideoStreamFramer(env, inputSource, iFramesOnly, vshPeriod, - False/*don't create a parser*/), - fLastNonBFrameTemporal_reference(0), - fSavedVSHSize(0), fSavedVSHTimestamp(0.0), - fIFramesOnly(iFramesOnly), fVSHPeriod(vshPeriod) { - fLastNonBFramePresentationTime.tv_sec = 0; - fLastNonBFramePresentationTime.tv_usec = 0; -} - -MPEG1or2VideoStreamDiscreteFramer::~MPEG1or2VideoStreamDiscreteFramer() { -} - -void MPEG1or2VideoStreamDiscreteFramer::doGetNextFrame() { - // Arrange to read data (which should be a complete MPEG-1 or 2 video frame) - // from our data source, directly into the client's input buffer. - // After reading this, we'll do some parsing on the frame. - fInputSource->getNextFrame(fTo, fMaxSize, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void MPEG1or2VideoStreamDiscreteFramer -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - MPEG1or2VideoStreamDiscreteFramer* source - = (MPEG1or2VideoStreamDiscreteFramer*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -static double const frameRateFromCode[] = { - 0.0, // forbidden - 24000/1001.0, // approx 23.976 - 24.0, - 25.0, - 30000/1001.0, // approx 29.97 - 30.0, - 50.0, - 60000/1001.0, // approx 59.94 - 60.0, - 0.0, // reserved - 0.0, // reserved - 0.0, // reserved - 0.0, // reserved - 0.0, // reserved - 0.0, // reserved - 0.0 // reserved -}; - -#define MILLION 1000000 - -void MPEG1or2VideoStreamDiscreteFramer -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Check that the first 4 bytes are a system code: - if (frameSize >= 4 && fTo[0] == 0 && fTo[1] == 0 && fTo[2] == 1) { - fPictureEndMarker = True; // Assume that we have a complete 'picture' here - - u_int8_t nextCode = fTo[3]; - if (nextCode == 0xB3) { // VIDEO_SEQUENCE_HEADER_START_CODE - // Note the following 'frame rate' code: - if (frameSize >= 8) { - u_int8_t frame_rate_code = fTo[7]&0x0F; - fFrameRate = frameRateFromCode[frame_rate_code]; - } - - // Also, save away this Video Sequence Header, in case we need it later: - // First, figure out how big it is: - unsigned vshSize; - for (vshSize = 4; vshSize < frameSize-3; ++vshSize) { - if (fTo[vshSize] == 0 && fTo[vshSize+1] == 0 && fTo[vshSize+2] == 1 && - (fTo[vshSize+3] == 0xB8 || fTo[vshSize+3] == 0x00)) break; - } - if (vshSize == frameSize-3) vshSize = frameSize; // There was nothing else following it - if (vshSize <= sizeof fSavedVSHBuffer) { - memmove(fSavedVSHBuffer, fTo, vshSize); - fSavedVSHSize = vshSize; - fSavedVSHTimestamp - = presentationTime.tv_sec + presentationTime.tv_usec/(double)MILLION; - } - } else if (nextCode == 0xB8) { // GROUP_START_CODE - // If necessary, insert a saved Video Sequence Header in front of this: - double pts = presentationTime.tv_sec + presentationTime.tv_usec/(double)MILLION; - if (pts > fSavedVSHTimestamp + fVSHPeriod && - fSavedVSHSize + frameSize <= fMaxSize) { - memmove(&fTo[fSavedVSHSize], &fTo[0], frameSize); // make room for the header - memmove(&fTo[0], fSavedVSHBuffer, fSavedVSHSize); // insert it - frameSize += fSavedVSHSize; - fSavedVSHTimestamp = pts; - } - } - - unsigned i = 3; - if (nextCode == 0xB3 /*VIDEO_SEQUENCE_HEADER_START_CODE*/ || - nextCode == 0xB8 /*GROUP_START_CODE*/) { - // Skip to the following PICTURE_START_CODE (if any): - for (i += 4; i < frameSize; ++i) { - if (fTo[i] == 0x00 /*PICTURE_START_CODE*/ - && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) { - nextCode = fTo[i]; - break; - } - } - } - - if (nextCode == 0x00 /*PICTURE_START_CODE*/ && i+2 < frameSize) { - // Get the 'temporal_reference' and 'picture_coding_type' from the - // following 2 bytes: - ++i; - unsigned short temporal_reference = (fTo[i]<<2)|(fTo[i+1]>>6); - unsigned char picture_coding_type = (fTo[i+1]&0x38)>>3; - - // If this is not an "I" frame, but we were asked for "I" frames only, then try again: - if (fIFramesOnly && picture_coding_type != 1) { - doGetNextFrame(); - return; - } - - // If this is a "B" frame, then we have to tweak "presentationTime": - if (picture_coding_type == 3/*B*/ - && (fLastNonBFramePresentationTime.tv_usec > 0 || - fLastNonBFramePresentationTime.tv_sec > 0)) { - int trIncrement - = fLastNonBFrameTemporal_reference - temporal_reference; - if (trIncrement < 0) trIncrement += 1024; // field is 10 bits in size - - unsigned usIncrement = fFrameRate == 0.0 ? 0 - : (unsigned)((trIncrement*MILLION)/fFrameRate); - unsigned secondsToSubtract = usIncrement/MILLION; - unsigned uSecondsToSubtract = usIncrement%MILLION; - - presentationTime = fLastNonBFramePresentationTime; - if ((unsigned)presentationTime.tv_usec < uSecondsToSubtract) { - presentationTime.tv_usec += MILLION; - if (presentationTime.tv_sec > 0) --presentationTime.tv_sec; - } - presentationTime.tv_usec -= uSecondsToSubtract; - if ((unsigned)presentationTime.tv_sec > secondsToSubtract) { - presentationTime.tv_sec -= secondsToSubtract; - } else { - presentationTime.tv_sec = presentationTime.tv_usec = 0; - } - } else { - fLastNonBFramePresentationTime = presentationTime; - fLastNonBFrameTemporal_reference = temporal_reference; - } - } - } - - // ##### Later: - // - do "iFramesOnly" if requested - - // Complete delivery to the client: - fFrameSize = frameSize; - fNumTruncatedBytes = numTruncatedBytes; - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - afterGetting(this); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoStreamFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoStreamFramer.cpp deleted file mode 100644 index b4c562e48b7..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG1or2VideoStreamFramer.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an MPEG 1 or 2 video elementary stream into -// frames for: Video_Sequence_Header, GOP_Header, Picture_Header -// Implementation - -#include "MPEG1or2VideoStreamFramer.hh" -#include "MPEGVideoStreamParser.hh" -#include - -////////// MPEG1or2VideoStreamParser definition ////////// - -// An enum representing the current state of the parser: -enum MPEGParseState { - PARSING_VIDEO_SEQUENCE_HEADER, - PARSING_VIDEO_SEQUENCE_HEADER_SEEN_CODE, - PARSING_GOP_HEADER, - PARSING_GOP_HEADER_SEEN_CODE, - PARSING_PICTURE_HEADER, - PARSING_SLICE -}; - -#define VSH_MAX_SIZE 1000 - -class MPEG1or2VideoStreamParser: public MPEGVideoStreamParser { -public: - MPEG1or2VideoStreamParser(MPEG1or2VideoStreamFramer* usingSource, - FramedSource* inputSource, - Boolean iFramesOnly, double vshPeriod); - virtual ~MPEG1or2VideoStreamParser(); - -private: // redefined virtual functions: - virtual void flushInput(); - virtual unsigned parse(); - -private: - void reset(); - - MPEG1or2VideoStreamFramer* usingSource() { - return (MPEG1or2VideoStreamFramer*)fUsingSource; - } - void setParseState(MPEGParseState parseState); - - unsigned parseVideoSequenceHeader(Boolean haveSeenStartCode); - unsigned parseGOPHeader(Boolean haveSeenStartCode); - unsigned parsePictureHeader(); - unsigned parseSlice(); - -private: - MPEGParseState fCurrentParseState; - unsigned fPicturesSinceLastGOP; - // can be used to compute timestamp for a video_sequence_header - unsigned short fCurPicTemporalReference; - // used to compute slice timestamp - unsigned char fCurrentSliceNumber; // set when parsing a slice - - // A saved copy of the most recently seen 'video_sequence_header', - // in case we need to insert it into the stream periodically: - unsigned char fSavedVSHBuffer[VSH_MAX_SIZE]; - unsigned fSavedVSHSize; - double fSavedVSHTimestamp; - double fVSHPeriod; - Boolean fIFramesOnly, fSkippingCurrentPicture; - - void saveCurrentVSH(); - Boolean needToUseSavedVSH(); - unsigned useSavedVSH(); // returns the size of the saved VSH -}; - - -////////// MPEG1or2VideoStreamFramer implementation ////////// - -MPEG1or2VideoStreamFramer::MPEG1or2VideoStreamFramer(UsageEnvironment& env, - FramedSource* inputSource, - Boolean iFramesOnly, - double vshPeriod, - Boolean createParser) - : MPEGVideoStreamFramer(env, inputSource) { - fParser = createParser - ? new MPEG1or2VideoStreamParser(this, inputSource, - iFramesOnly, vshPeriod) - : NULL; -} - -MPEG1or2VideoStreamFramer::~MPEG1or2VideoStreamFramer() { -} - -MPEG1or2VideoStreamFramer* -MPEG1or2VideoStreamFramer::createNew(UsageEnvironment& env, - FramedSource* inputSource, - Boolean iFramesOnly, - double vshPeriod) { - // Need to add source type checking here??? ##### - return new MPEG1or2VideoStreamFramer(env, inputSource, iFramesOnly, vshPeriod); -} - -double MPEG1or2VideoStreamFramer::getCurrentPTS() const { - return fPresentationTime.tv_sec + fPresentationTime.tv_usec/1000000.0; -} - -Boolean MPEG1or2VideoStreamFramer::isMPEG1or2VideoStreamFramer() const { - return True; -} - -////////// MPEG1or2VideoStreamParser implementation ////////// - -MPEG1or2VideoStreamParser -::MPEG1or2VideoStreamParser(MPEG1or2VideoStreamFramer* usingSource, - FramedSource* inputSource, - Boolean iFramesOnly, double vshPeriod) - : MPEGVideoStreamParser(usingSource, inputSource), - fCurrentParseState(PARSING_VIDEO_SEQUENCE_HEADER), - fVSHPeriod(vshPeriod), fIFramesOnly(iFramesOnly) { - reset(); -} - -MPEG1or2VideoStreamParser::~MPEG1or2VideoStreamParser() { -} - -void MPEG1or2VideoStreamParser::setParseState(MPEGParseState parseState) { - fCurrentParseState = parseState; - MPEGVideoStreamParser::setParseState(); -} - -void MPEG1or2VideoStreamParser::reset() { - fPicturesSinceLastGOP = 0; - fCurPicTemporalReference = 0; - fCurrentSliceNumber = 0; - fSavedVSHSize = 0; - fSkippingCurrentPicture = False; -} - -void MPEG1or2VideoStreamParser::flushInput() { - reset(); - StreamParser::flushInput(); - if (fCurrentParseState != PARSING_VIDEO_SEQUENCE_HEADER) { - setParseState(PARSING_GOP_HEADER); // start from the next GOP - } -} - -unsigned MPEG1or2VideoStreamParser::parse() { - try { - switch (fCurrentParseState) { - case PARSING_VIDEO_SEQUENCE_HEADER: { - return parseVideoSequenceHeader(False); - } - case PARSING_VIDEO_SEQUENCE_HEADER_SEEN_CODE: { - return parseVideoSequenceHeader(True); - } - case PARSING_GOP_HEADER: { - return parseGOPHeader(False); - } - case PARSING_GOP_HEADER_SEEN_CODE: { - return parseGOPHeader(True); - } - case PARSING_PICTURE_HEADER: { - return parsePictureHeader(); - } - case PARSING_SLICE: { - return parseSlice(); - } - default: { - return 0; // shouldn't happen - } - } - } catch (int /*e*/) { -#ifdef DEBUG - fprintf(stderr, "MPEG1or2VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n"); -#endif - return 0; // the parsing got interrupted - } -} - -void MPEG1or2VideoStreamParser::saveCurrentVSH() { - unsigned frameSize = curFrameSize(); - if (frameSize > sizeof fSavedVSHBuffer) return; // too big to save - - memmove(fSavedVSHBuffer, fStartOfFrame, frameSize); - fSavedVSHSize = frameSize; - fSavedVSHTimestamp = usingSource()->getCurrentPTS(); -} - -Boolean MPEG1or2VideoStreamParser::needToUseSavedVSH() { - return usingSource()->getCurrentPTS() > fSavedVSHTimestamp+fVSHPeriod - && fSavedVSHSize > 0; -} - -unsigned MPEG1or2VideoStreamParser::useSavedVSH() { - unsigned bytesToUse = fSavedVSHSize; - unsigned maxBytesToUse = fLimit - fStartOfFrame; - if (bytesToUse > maxBytesToUse) bytesToUse = maxBytesToUse; - - memmove(fStartOfFrame, fSavedVSHBuffer, bytesToUse); - - // Also reset the saved timestamp: - fSavedVSHTimestamp = usingSource()->getCurrentPTS(); - -#ifdef DEBUG - fprintf(stderr, "used saved video_sequence_header (%d bytes)\n", bytesToUse); -#endif - return bytesToUse; -} - -#define VIDEO_SEQUENCE_HEADER_START_CODE 0x000001B3 -#define GROUP_START_CODE 0x000001B8 -#define PICTURE_START_CODE 0x00000100 -#define SEQUENCE_END_CODE 0x000001B7 - -static double const frameRateFromCode[] = { - 0.0, // forbidden - 24000/1001.0, // approx 23.976 - 24.0, - 25.0, - 30000/1001.0, // approx 29.97 - 30.0, - 50.0, - 60000/1001.0, // approx 59.94 - 60.0, - 0.0, // reserved - 0.0, // reserved - 0.0, // reserved - 0.0, // reserved - 0.0, // reserved - 0.0, // reserved - 0.0 // reserved -}; - -unsigned MPEG1or2VideoStreamParser -::parseVideoSequenceHeader(Boolean haveSeenStartCode) { -#ifdef DEBUG - fprintf(stderr, "parsing video sequence header\n"); -#endif - unsigned first4Bytes; - if (!haveSeenStartCode) { - while ((first4Bytes = test4Bytes()) != VIDEO_SEQUENCE_HEADER_START_CODE) { -#ifdef DEBUG - fprintf(stderr, "ignoring non video sequence header: 0x%08x\n", first4Bytes); -#endif - get1Byte(); setParseState(PARSING_VIDEO_SEQUENCE_HEADER); - // ensures we progress over bad data - } - first4Bytes = get4Bytes(); - } else { - // We've already seen the start code - first4Bytes = VIDEO_SEQUENCE_HEADER_START_CODE; - } - save4Bytes(first4Bytes); - - // Next, extract the size and rate parameters from the next 8 bytes - unsigned paramWord1 = get4Bytes(); - save4Bytes(paramWord1); - unsigned next4Bytes = get4Bytes(); -#ifdef DEBUG - unsigned short horizontal_size_value = (paramWord1&0xFFF00000)>>(32-12); - unsigned short vertical_size_value = (paramWord1&0x000FFF00)>>8; - unsigned char aspect_ratio_information = (paramWord1&0x000000F0)>>4; -#endif - unsigned char frame_rate_code = (paramWord1&0x0000000F); - usingSource()->fFrameRate = frameRateFromCode[frame_rate_code]; -#ifdef DEBUG - unsigned bit_rate_value = (next4Bytes&0xFFFFC000)>>(32-18); - unsigned vbv_buffer_size_value = (next4Bytes&0x00001FF8)>>3; - fprintf(stderr, "horizontal_size_value: %d, vertical_size_value: %d, aspect_ratio_information: %d, frame_rate_code: %d (=>%f fps), bit_rate_value: %d (=>%d bps), vbv_buffer_size_value: %d\n", horizontal_size_value, vertical_size_value, aspect_ratio_information, frame_rate_code, usingSource()->fFrameRate, bit_rate_value, bit_rate_value*400, vbv_buffer_size_value); -#endif - - // Now, copy all bytes that we see, up until we reach a GROUP_START_CODE - // or a PICTURE_START_CODE: - do { - saveToNextCode(next4Bytes); - } while (next4Bytes != GROUP_START_CODE && next4Bytes != PICTURE_START_CODE); - - setParseState((next4Bytes == GROUP_START_CODE) - ? PARSING_GOP_HEADER_SEEN_CODE : PARSING_PICTURE_HEADER); - - // Compute this frame's timestamp by noting how many pictures we've seen - // since the last GOP header: - usingSource()->computePresentationTime(fPicturesSinceLastGOP); - - // Save this video_sequence_header, in case we need to insert a copy - // into the stream later: - saveCurrentVSH(); - - return curFrameSize(); -} - -unsigned MPEG1or2VideoStreamParser::parseGOPHeader(Boolean haveSeenStartCode) { - // First check whether we should insert a previously-saved - // 'video_sequence_header' here: - if (needToUseSavedVSH()) return useSavedVSH(); - -#ifdef DEBUG - fprintf(stderr, "parsing GOP header\n"); -#endif - unsigned first4Bytes; - if (!haveSeenStartCode) { - while ((first4Bytes = test4Bytes()) != GROUP_START_CODE) { -#ifdef DEBUG - fprintf(stderr, "ignoring non GOP start code: 0x%08x\n", first4Bytes); -#endif - get1Byte(); setParseState(PARSING_GOP_HEADER); - // ensures we progress over bad data - } - first4Bytes = get4Bytes(); - } else { - // We've already seen the GROUP_START_CODE - first4Bytes = GROUP_START_CODE; - } - save4Bytes(first4Bytes); - - // Next, extract the (25-bit) time code from the next 4 bytes: - unsigned next4Bytes = get4Bytes(); - unsigned time_code = (next4Bytes&0xFFFFFF80)>>(32-25); -#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS) - Boolean drop_frame_flag = (time_code&0x01000000) != 0; -#endif - unsigned time_code_hours = (time_code&0x00F80000)>>19; - unsigned time_code_minutes = (time_code&0x0007E000)>>13; - unsigned time_code_seconds = (time_code&0x00000FC0)>>6; - unsigned time_code_pictures = (time_code&0x0000003F); -#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS) - fprintf(stderr, "time_code: 0x%07x, drop_frame %d, hours %d, minutes %d, seconds %d, pictures %d\n", time_code, drop_frame_flag, time_code_hours, time_code_minutes, time_code_seconds, time_code_pictures); -#endif -#ifdef DEBUG - Boolean closed_gop = (next4Bytes&0x00000040) != 0; - Boolean broken_link = (next4Bytes&0x00000020) != 0; - fprintf(stderr, "closed_gop: %d, broken_link: %d\n", closed_gop, broken_link); -#endif - - // Now, copy all bytes that we see, up until we reach a PICTURE_START_CODE: - do { - saveToNextCode(next4Bytes); - } while (next4Bytes != PICTURE_START_CODE); - - // Record the time code: - usingSource()->setTimeCode(time_code_hours, time_code_minutes, - time_code_seconds, time_code_pictures, - fPicturesSinceLastGOP); - - fPicturesSinceLastGOP = 0; - - // Compute this frame's timestamp: - usingSource()->computePresentationTime(0); - - setParseState(PARSING_PICTURE_HEADER); - - return curFrameSize(); -} - -inline Boolean isSliceStartCode(unsigned fourBytes) { - if ((fourBytes&0xFFFFFF00) != 0x00000100) return False; - - unsigned char lastByte = fourBytes&0xFF; - return lastByte <= 0xAF && lastByte >= 1; -} - -unsigned MPEG1or2VideoStreamParser::parsePictureHeader() { -#ifdef DEBUG - fprintf(stderr, "parsing picture header\n"); -#endif - // Note that we've already read the PICTURE_START_CODE - // Next, extract the temporal reference from the next 4 bytes: - unsigned next4Bytes = get4Bytes(); - unsigned short temporal_reference = (next4Bytes&0xFFC00000)>>(32-10); - unsigned char picture_coding_type = (next4Bytes&0x00380000)>>19; -#ifdef DEBUG - unsigned short vbv_delay = (next4Bytes&0x0007FFF8)>>3; - fprintf(stderr, "temporal_reference: %d, picture_coding_type: %d, vbv_delay: %d\n", temporal_reference, picture_coding_type, vbv_delay); -#endif - - fSkippingCurrentPicture = fIFramesOnly && picture_coding_type != 1; - if (fSkippingCurrentPicture) { - // Skip all bytes that we see, up until we reach a slice_start_code: - do { - skipToNextCode(next4Bytes); - } while (!isSliceStartCode(next4Bytes)); - } else { - // Save the PICTURE_START_CODE that we've already read: - save4Bytes(PICTURE_START_CODE); - - // Copy all bytes that we see, up until we reach a slice_start_code: - do { - saveToNextCode(next4Bytes); - } while (!isSliceStartCode(next4Bytes)); - } - - setParseState(PARSING_SLICE); - - fCurrentSliceNumber = next4Bytes&0xFF; - - // Record the temporal reference: - fCurPicTemporalReference = temporal_reference; - - // Compute this frame's timestamp: - usingSource()->computePresentationTime(fCurPicTemporalReference); - - if (fSkippingCurrentPicture) { - return parse(); // try again, until we get a non-skipped frame - } else { - return curFrameSize(); - } -} - -unsigned MPEG1or2VideoStreamParser::parseSlice() { - // Note that we've already read the slice_start_code: - unsigned next4Bytes = PICTURE_START_CODE|fCurrentSliceNumber; -#ifdef DEBUG_SLICE - fprintf(stderr, "parsing slice: 0x%08x\n", next4Bytes); -#endif - - if (fSkippingCurrentPicture) { - // Skip all bytes that we see, up until we reach a code of some sort: - skipToNextCode(next4Bytes); - } else { - // Copy all bytes that we see, up until we reach a code of some sort: - saveToNextCode(next4Bytes); - } - - // The next thing to parse depends on the code that we just saw: - if (isSliceStartCode(next4Bytes)) { // common case - setParseState(PARSING_SLICE); - fCurrentSliceNumber = next4Bytes&0xFF; - } else { - // Because we don't see any more slices, we are assumed to have ended - // the current picture: - ++fPicturesSinceLastGOP; - ++usingSource()->fPictureCount; - usingSource()->fPictureEndMarker = True; // HACK ##### - - switch (next4Bytes) { - case SEQUENCE_END_CODE: { - setParseState(PARSING_VIDEO_SEQUENCE_HEADER); - break; - } - case VIDEO_SEQUENCE_HEADER_START_CODE: { - setParseState(PARSING_VIDEO_SEQUENCE_HEADER_SEEN_CODE); - break; - } - case GROUP_START_CODE: { - setParseState(PARSING_GOP_HEADER_SEEN_CODE); - break; - } - case PICTURE_START_CODE: { - setParseState(PARSING_PICTURE_HEADER); - break; - } - default: { - usingSource()->envir() << "MPEG1or2VideoStreamParser::parseSlice(): Saw unexpected code " - << (void*)next4Bytes << "\n"; - setParseState(PARSING_SLICE); // the safest way to recover... - break; - } - } - } - - // Compute this frame's timestamp: - usingSource()->computePresentationTime(fCurPicTemporalReference); - - if (fSkippingCurrentPicture) { - return parse(); // try again, until we get a non-skipped frame - } else { - return curFrameSize(); - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportFileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportFileServerMediaSubsession.cpp deleted file mode 100644 index 8098a5ffcab..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportFileServerMediaSubsession.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-2 Transport Stream file. -// Implementation - -#include "MPEG2TransportFileServerMediaSubsession.hh" -#include "SimpleRTPSink.hh" -#include "ByteStreamFileSource.hh" -#include "MPEG2TransportStreamFramer.hh" - -MPEG2TransportFileServerMediaSubsession* -MPEG2TransportFileServerMediaSubsession::createNew(UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource) { - return new MPEG2TransportFileServerMediaSubsession(env, fileName, reuseFirstSource); -} - -MPEG2TransportFileServerMediaSubsession -::MPEG2TransportFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource) - : FileServerMediaSubsession(env, fileName, reuseFirstSource) { -} - -MPEG2TransportFileServerMediaSubsession -::~MPEG2TransportFileServerMediaSubsession() { -} - -#define TRANSPORT_PACKET_SIZE 188 -#define TRANSPORT_PACKETS_PER_NETWORK_PACKET 7 -// The product of these two numbers must be enough to fit within a network packet - -FramedSource* MPEG2TransportFileServerMediaSubsession -::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) { - estBitrate = 5000; // kbps, estimate - - // Create the video source: - unsigned const inputDataChunkSize - = TRANSPORT_PACKETS_PER_NETWORK_PACKET*TRANSPORT_PACKET_SIZE; - ByteStreamFileSource* fileSource - = ByteStreamFileSource::createNew(envir(), fFileName, inputDataChunkSize); - if (fileSource == NULL) return NULL; - fFileSize = fileSource->fileSize(); - - // Create a framer for the Transport Stream: - return MPEG2TransportStreamFramer::createNew(envir(), fileSource); -} - -RTPSink* MPEG2TransportFileServerMediaSubsession -::createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char /*rtpPayloadTypeIfDynamic*/, - FramedSource* /*inputSource*/) { - return SimpleRTPSink::createNew(envir(), rtpGroupsock, - 33, 90000, "video", "mp2t", - 1, True, False /*no 'M' bit*/); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFramer.cpp deleted file mode 100644 index 5ee3f873963..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFramer.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// A filter that passes through (unchanged) chunks that contain an integral number -// of MPEG-2 Transport Stream packets, but returning (in "fDurationInMicroseconds") -// an updated estimate of the time gap between chunks. -// Implementation - -#include "MPEG2TransportStreamFramer.hh" -#include // for "gettimeofday()" - -#define TRANSPORT_PACKET_SIZE 188 -#define NEW_DURATION_WEIGHT 0.5 - // How much weight to give to the latest duration measurement (must be <= 1) -#define TIME_ADJUSTMENT_FACTOR 0.8 - // A factor by which to adjust the duration estimate to ensure that the overall - // packet transmission times remains matched with the PCR times (which will be the - // times that we expect receivers to play the incoming packets). - // (must be <= 1) -#define MAX_PLAYOUT_BUFFER_DURATION 0.1 // (seconds) - -////////// PIDStatus ////////// - -class PIDStatus { -public: - PIDStatus(double _firstClock, double _firstRealTime) - : firstClock(_firstClock), lastClock(_firstClock), - firstRealTime(_firstRealTime), lastRealTime(_firstRealTime), - lastPacketNum(0) { - } - - double firstClock, lastClock, firstRealTime, lastRealTime; - unsigned lastPacketNum; -}; - - -////////// MPEG2TransportStreamFramer ////////// - -MPEG2TransportStreamFramer* MPEG2TransportStreamFramer -::createNew(UsageEnvironment& env, FramedSource* inputSource) { - return new MPEG2TransportStreamFramer(env, inputSource); -} - -MPEG2TransportStreamFramer -::MPEG2TransportStreamFramer(UsageEnvironment& env, FramedSource* inputSource) - : FramedFilter(env, inputSource), - fTSPacketCount(0), fTSPacketDurationEstimate(0.0) { - fPIDStatusTable = HashTable::create(ONE_WORD_HASH_KEYS); -} - -MPEG2TransportStreamFramer::~MPEG2TransportStreamFramer() { - PIDStatus* pidStatus; - while ((pidStatus = (PIDStatus*)fPIDStatusTable->RemoveNext()) != NULL) { - delete pidStatus; - } - delete fPIDStatusTable; -} - -void MPEG2TransportStreamFramer::doGetNextFrame() { - // Read directly from our input source into our client's buffer: - fFrameSize = 0; - fInputSource->getNextFrame(fTo, fMaxSize, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void MPEG2TransportStreamFramer::doStopGettingFrames() { - FramedFilter::doStopGettingFrames(); - fTSPacketCount = 0; - - // Clear out the existing PID status table: - PIDStatus* pidStatus; - while ((pidStatus = (PIDStatus*)fPIDStatusTable->RemoveNext()) != NULL) { - delete pidStatus; - } -} - -void MPEG2TransportStreamFramer -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - MPEG2TransportStreamFramer* framer = (MPEG2TransportStreamFramer*)clientData; - framer->afterGettingFrame1(frameSize, presentationTime); -} - -#define TRANSPORT_SYNC_BYTE 0x47 - -void MPEG2TransportStreamFramer::afterGettingFrame1(unsigned frameSize, - struct timeval presentationTime) { - fFrameSize += frameSize; - unsigned const numTSPackets = fFrameSize/TRANSPORT_PACKET_SIZE; - fFrameSize = numTSPackets*TRANSPORT_PACKET_SIZE; // an integral # of TS packets - if (fFrameSize == 0) { - // We didn't read a complete TS packet; assume that the input source has closed. - handleClosure(this); - return; - } - - // Make sure the data begins with a sync byte: - unsigned syncBytePosition; - for (syncBytePosition = 0; syncBytePosition < fFrameSize; ++syncBytePosition) { - if (fTo[syncBytePosition] == TRANSPORT_SYNC_BYTE) break; - } - if (syncBytePosition == fFrameSize) { - envir() << "No Transport Stream sync byte in data."; - handleClosure(this); - return; - } else if (syncBytePosition > 0) { - // There's a sync byte, but not at the start of the data. Move the good data - // to the start of the buffer, then read more to fill it up again: - memmove(fTo, &fTo[syncBytePosition], fFrameSize - syncBytePosition); - fFrameSize -= syncBytePosition; - fInputSource->getNextFrame(&fTo[fFrameSize], syncBytePosition, - afterGettingFrame, this, - FramedSource::handleClosure, this); - return; - } // else normal case: the data begins with a sync byte - - fPresentationTime = presentationTime; - - // Scan through the TS packets that we read, and update our estimate of - // the duration of each packet: - struct timeval tvNow; - gettimeofday(&tvNow, NULL); - double timeNow = tvNow.tv_sec + tvNow.tv_usec/1000000.0; - for (unsigned i = 0; i < numTSPackets; ++i) { - updateTSPacketDurationEstimate(&fTo[i*TRANSPORT_PACKET_SIZE], timeNow); - } - - fDurationInMicroseconds - = numTSPackets * (unsigned)(fTSPacketDurationEstimate*1000000); - - // Complete the delivery to our client: - afterGetting(this); -} - -void MPEG2TransportStreamFramer -::updateTSPacketDurationEstimate(unsigned char* pkt, double timeNow) { - // Sanity check: Make sure we start with the sync byte: - if (pkt[0] != TRANSPORT_SYNC_BYTE) { - envir() << "Missing sync byte!\n"; - return; - } - - ++fTSPacketCount; - - // If this packet doesn't contain a PCR, then we're not interested in it: - u_int8_t const adaptation_field_control = (pkt[3]&0x30)>>4; - if (adaptation_field_control != 2 && adaptation_field_control != 3) return; - // there's no adaptation_field - - u_int8_t const adaptation_field_length = pkt[4]; - if (adaptation_field_length == 0) return; - - u_int8_t const discontinuity_indicator = pkt[5]&0x80; - u_int8_t const pcrFlag = pkt[5]&0x10; - if (pcrFlag == 0) return; // no PCR - - // There's a PCR. Get it, and the PID: - u_int32_t pcrBaseHigh = (pkt[6]<<24)|(pkt[7]<<16)|(pkt[8]<<8)|pkt[9]; - double clock = pcrBaseHigh/45000.0; - if ((pkt[10]&0x80) != 0) clock += 1/90000.0; // add in low-bit (if set) - unsigned short pcrExt = ((pkt[10]&0x01)<<8) | pkt[11]; - clock += pcrExt/27000000.0; - - unsigned pid = ((pkt[1]&0x1F)<<8) | pkt[2]; - - // Check whether we already have a record of a PCR for this PID: - PIDStatus* pidStatus = (PIDStatus*)(fPIDStatusTable->Lookup((char*)pid)); - if (pidStatus == NULL) { - // We're seeing this PID's PCR for the first time: - pidStatus = new PIDStatus(clock, timeNow); - fPIDStatusTable->Add((char*)pid, pidStatus); -#ifdef DEBUG_PCR - fprintf(stderr, "PID 0x%x, FIRST PCR 0x%08x+%d:%03x == %f @ %f, pkt #%lu\n", pid, pcrBaseHigh, pkt[10]>>7, pcrExt, clock, timeNow, fTSPacketCount); -#endif - } else { - // We've seen this PID's PCR before; update our per-packet duration estimate: - double durationPerPacket - = (clock - pidStatus->lastClock)/(fTSPacketCount - pidStatus->lastPacketNum); - if (fTSPacketDurationEstimate == 0.0) { // we've just started - fTSPacketDurationEstimate = durationPerPacket; - } else if (discontinuity_indicator == 0 && durationPerPacket >= 0.0) { - fTSPacketDurationEstimate - = durationPerPacket*NEW_DURATION_WEIGHT - + fTSPacketDurationEstimate*(1-NEW_DURATION_WEIGHT); - - // Also adjust the duration estimate to try to ensure that the transmission - // rate matches the playout rate: - double transmitDuration = timeNow - pidStatus->firstRealTime; - double playoutDuration = clock - pidStatus->firstClock; - if (transmitDuration > playoutDuration) { - fTSPacketDurationEstimate *= TIME_ADJUSTMENT_FACTOR; // reduce estimate - } else if (transmitDuration + MAX_PLAYOUT_BUFFER_DURATION < playoutDuration) { - fTSPacketDurationEstimate /= TIME_ADJUSTMENT_FACTOR; // increase estimate - } - } else { - // the PCR has a discontinuity from its previous value; don't use it now, - // but reset our PCR and real-time values to compensate: - pidStatus->firstClock = clock; - pidStatus->firstRealTime = timeNow; - } -#ifdef DEBUG_PCR - fprintf(stderr, "PID 0x%x, PCR 0x%08x+%d:%03x == %f @ %f (diffs %f @ %f), pkt #%lu, discon %d => this duration %f, new estimate %f\n", pid, pcrBaseHigh, pkt[10]>>7, pcrExt, clock, timeNow, clock - pidStatus->firstClock, timeNow - pidStatus->firstRealTime, fTSPacketCount, discontinuity_indicator != 0, durationPerPacket, fTSPacketDurationEstimate); -#endif - } - - pidStatus->lastClock = clock; - pidStatus->lastRealTime = timeNow; - pidStatus->lastPacketNum = fTSPacketCount; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFromESSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFromESSource.cpp deleted file mode 100644 index 6ab237d282d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFromESSource.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter for converting one or more MPEG Elementary Streams -// to a MPEG-2 Transport Stream -// Implementation - -#include "MPEG2TransportStreamFromESSource.hh" - -#define MAX_INPUT_ES_FRAME_SIZE 50000 -#define SIMPLE_PES_HEADER_SIZE 14 -#define LOW_WATER_MARK 1000 // <= MAX_INPUT_ES_FRAME_SIZE -#define INPUT_BUFFER_SIZE (SIMPLE_PES_HEADER_SIZE + 2*MAX_INPUT_ES_FRAME_SIZE) - -////////// InputESSourceRecord definition ////////// - -class InputESSourceRecord { -public: - InputESSourceRecord(MPEG2TransportStreamFromESSource& parent, - FramedSource* inputSource, - u_int8_t streamId, int mpegVersion, - InputESSourceRecord* next); - virtual ~InputESSourceRecord(); - - InputESSourceRecord* next() const { return fNext; } - FramedSource* inputSource() const { return fInputSource; } - - void askForNewData(); - Boolean deliverBufferToClient(); - - unsigned char* buffer() const { return fInputBuffer; } - void reset() { - // Reset the buffer for future use: - fInputBufferBytesAvailable = 0; - fInputBufferInUse = False; - } - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime); - -private: - InputESSourceRecord* fNext; - MPEG2TransportStreamFromESSource& fParent; - FramedSource* fInputSource; - u_int8_t fStreamId; - int fMPEGVersion; - unsigned char* fInputBuffer; - unsigned fInputBufferBytesAvailable; - Boolean fInputBufferInUse; - MPEG1or2Demux::SCR fSCR; -}; - - -////////// MPEG2TransportStreamFromESSource implementation ////////// - -MPEG2TransportStreamFromESSource* MPEG2TransportStreamFromESSource -::createNew(UsageEnvironment& env) { - return new MPEG2TransportStreamFromESSource(env); -} - -void MPEG2TransportStreamFromESSource -::addNewVideoSource(FramedSource* inputSource, int mpegVersion) { - u_int8_t streamId = 0xE0 | (fVideoSourceCounter++&0x0F); - addNewInputSource(inputSource, streamId, mpegVersion); - fHaveVideoStreams = True; -} - -void MPEG2TransportStreamFromESSource -::addNewAudioSource(FramedSource* inputSource, int mpegVersion) { - u_int8_t streamId = 0xC0 | (fVideoSourceCounter++&0x0F); - addNewInputSource(inputSource, streamId, mpegVersion); -} - -MPEG2TransportStreamFromESSource -::MPEG2TransportStreamFromESSource(UsageEnvironment& env) - : MPEG2TransportStreamMultiplexor(env), - fInputSources(NULL), fVideoSourceCounter(0), fAudioSourceCounter(0) { - fHaveVideoStreams = False; // unless we add a video source -} - -MPEG2TransportStreamFromESSource::~MPEG2TransportStreamFromESSource() { - delete fInputSources; -} - -void MPEG2TransportStreamFromESSource::doStopGettingFrames() { - // Stop each input source: - for (InputESSourceRecord* sourceRec = fInputSources; sourceRec != NULL; - sourceRec = sourceRec->next()) { - sourceRec->inputSource()->stopGettingFrames(); - } -} - -void MPEG2TransportStreamFromESSource -::awaitNewBuffer(unsigned char* oldBuffer) { - InputESSourceRecord* sourceRec; - // Begin by resetting the old buffer: - if (oldBuffer != NULL) { - for (sourceRec = fInputSources; sourceRec != NULL; - sourceRec = sourceRec->next()) { - if (sourceRec->buffer() == oldBuffer) { - sourceRec->reset(); - break; - } - } - } - - if (isCurrentlyAwaitingData()) { - // Try to deliver one filled-in buffer to the client: - for (sourceRec = fInputSources; sourceRec != NULL; - sourceRec = sourceRec->next()) { - if (sourceRec->deliverBufferToClient()) break; - } - } - - // No filled-in buffers are available. Ask each of our inputs for data: - for (sourceRec = fInputSources; sourceRec != NULL; - sourceRec = sourceRec->next()) { - sourceRec->askForNewData(); - } - -} - -void MPEG2TransportStreamFromESSource -::addNewInputSource(FramedSource* inputSource, - u_int8_t streamId, int mpegVersion) { - if (inputSource == NULL) return; - fInputSources = new InputESSourceRecord(*this, inputSource, streamId, - mpegVersion, fInputSources); -} - - -////////// InputESSourceRecord implementation ////////// - -InputESSourceRecord -::InputESSourceRecord(MPEG2TransportStreamFromESSource& parent, - FramedSource* inputSource, - u_int8_t streamId, int mpegVersion, - InputESSourceRecord* next) - : fNext(next), fParent(parent), fInputSource(inputSource), - fStreamId(streamId), fMPEGVersion(mpegVersion) { - fInputBuffer = new unsigned char[INPUT_BUFFER_SIZE]; - reset(); -} - -InputESSourceRecord::~InputESSourceRecord() { - Medium::close(fInputSource); - delete[] fInputBuffer; - delete fNext; -} - -void InputESSourceRecord::askForNewData() { - if (fInputBufferInUse) return; - - if (fInputBufferBytesAvailable == 0) { - // Reset our buffer, by adding a simple PES header at the start: - fInputBuffer[0] = 0; fInputBuffer[1] = 0; fInputBuffer[2] = 1; - fInputBuffer[3] = fStreamId; - fInputBuffer[4] = 0; fInputBuffer[5] = 0; // fill in later with the length - fInputBuffer[6] = 0x80; - fInputBuffer[7] = 0x80; // include a PTS - fInputBuffer[8] = 5; // PES_header_data_length (enough for a PTS) - // fInputBuffer[9..13] will be the PTS; fill this in later - fInputBufferBytesAvailable = SIMPLE_PES_HEADER_SIZE; - } - if (fInputBufferBytesAvailable < LOW_WATER_MARK && - !fInputSource->isCurrentlyAwaitingData()) { - // We don't yet have enough data in our buffer. Arrange to read more: - fInputSource->getNextFrame(&fInputBuffer[fInputBufferBytesAvailable], - INPUT_BUFFER_SIZE-fInputBufferBytesAvailable, - afterGettingFrame, this, - FramedSource::handleClosure, &fParent); - } -} - -Boolean InputESSourceRecord::deliverBufferToClient() { - if (fInputBufferInUse || fInputBufferBytesAvailable < LOW_WATER_MARK) return False; - - // Fill in the PES_packet_length field that we left unset before: - unsigned PES_packet_length = fInputBufferBytesAvailable - 6; - fInputBuffer[4] = PES_packet_length>>8; - fInputBuffer[5] = PES_packet_length; - - // Fill in the PES PTS (from our SCR): - fInputBuffer[9] = 0x20|(fSCR.highBit<<3)|(fSCR.remainingBits>>29)|0x01; - fInputBuffer[10] = fSCR.remainingBits>>22; - fInputBuffer[11] = (fSCR.remainingBits>>14)|0x01; - fInputBuffer[12] = fSCR.remainingBits>>7; - fInputBuffer[13] = (fSCR.remainingBits<<1)|0x01; - - fInputBufferInUse = True; - - // Do the delivery: - fParent.handleNewBuffer(fInputBuffer, fInputBufferBytesAvailable, - fMPEGVersion, fSCR); - - return True; -} - -void InputESSourceRecord -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - InputESSourceRecord* source = (InputESSourceRecord*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime); -} -void InputESSourceRecord -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime) { - if (numTruncatedBytes > 0) { - fParent.envir() << "MPEG2TransportStreamFromESSource: input buffer too small; increase \"MAX_INPUT_ES_FRAME_SIZE\" in \"MPEG2TransportStreamFromESSource\" by at least " - << numTruncatedBytes << " bytes!\n"; - } - - if (fInputBufferBytesAvailable == SIMPLE_PES_HEADER_SIZE) { - // Use this presentationTime for our SCR: - fSCR.highBit - = ((presentationTime.tv_sec*45000 + (presentationTime.tv_usec*9)/200)& - 0x80000000) != 0; - fSCR.remainingBits - = presentationTime.tv_sec*90000 + (presentationTime.tv_usec*9)/100; - fSCR.extension = (presentationTime.tv_usec*9)%100; -#ifdef DEBUG_SCR - fprintf(stderr, "PES header: stream_id 0x%02x, pts: %u.%06u => SCR 0x%x%08x:%03x\n", fStreamId, (unsigned)presentationTime.tv_sec, (unsigned)presentationTime.tv_usec, fSCR.highBit, fSCR.remainingBits, fSCR.extension); -#endif - } - - fInputBufferBytesAvailable += frameSize; - - // Now that we have new input data, check if we can deliver to the client: - fParent.awaitNewBuffer(NULL); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFromPESSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFromPESSource.cpp deleted file mode 100644 index a370f905ed4..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamFromPESSource.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter for converting a stream of MPEG PES packets to a MPEG-2 Transport Stream -// Implementation - -#include "MPEG2TransportStreamFromPESSource.hh" - -#define MAX_PES_PACKET_SIZE 65536 - -MPEG2TransportStreamFromPESSource* MPEG2TransportStreamFromPESSource -::createNew(UsageEnvironment& env, MPEG1or2DemuxedElementaryStream* inputSource) { - return new MPEG2TransportStreamFromPESSource(env, inputSource); -} - -MPEG2TransportStreamFromPESSource -::MPEG2TransportStreamFromPESSource(UsageEnvironment& env, - MPEG1or2DemuxedElementaryStream* inputSource) - : MPEG2TransportStreamMultiplexor(env), - fInputSource(inputSource) { - fInputBuffer = new unsigned char[MAX_PES_PACKET_SIZE]; -} - -MPEG2TransportStreamFromPESSource::~MPEG2TransportStreamFromPESSource() { - Medium::close(fInputSource); - delete[] fInputBuffer; -} - -void MPEG2TransportStreamFromPESSource::doStopGettingFrames() { - fInputSource->stopGettingFrames(); -} - -void MPEG2TransportStreamFromPESSource -::awaitNewBuffer(unsigned char* /*oldBuffer*/) { - fInputSource->getNextFrame(fInputBuffer, MAX_PES_PACKET_SIZE, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void MPEG2TransportStreamFromPESSource -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - MPEG2TransportStreamFromPESSource* source - = (MPEG2TransportStreamFromPESSource*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -void MPEG2TransportStreamFromPESSource -::afterGettingFrame1(unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval /*presentationTime*/, - unsigned /*durationInMicroseconds*/) { - if (frameSize < 4) return; - - handleNewBuffer(fInputBuffer, frameSize, - fInputSource->mpegVersion(), fInputSource->lastSeenSCR()); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamMultiplexor.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamMultiplexor.cpp deleted file mode 100644 index 94895482676..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG2TransportStreamMultiplexor.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A class for generating MPEG-2 Transport Stream from one or more input -// Elementary Stream data sources -// Implementation - -#include "MPEG2TransportStreamMultiplexor.hh" - -#define TRANSPORT_PACKET_SIZE 188 - -#define PAT_FREQUENCY 100 // # of packets between Program Association Tables -#define PMT_FREQUENCY 500 // # of packets between Program Map Tables - -#define PID_TABLE_SIZE 256 - -MPEG2TransportStreamMultiplexor -::MPEG2TransportStreamMultiplexor(UsageEnvironment& env) - : FramedSource(env), - fHaveVideoStreams(True/*by default*/), - fOutgoingPacketCounter(0), fProgramMapVersion(0), - fPreviousInputProgramMapVersion(0xFF), fCurrentInputProgramMapVersion(0xFF), - fPCR_PID(0), fCurrentPID(0), - fInputBuffer(NULL), fInputBufferSize(0), fInputBufferBytesUsed(0) { - for (unsigned i = 0; i < PID_TABLE_SIZE; ++i) { - fPIDState[i].counter = 0; - fPIDState[i].streamType = 0; - } -} - -MPEG2TransportStreamMultiplexor::~MPEG2TransportStreamMultiplexor() { -} - -void MPEG2TransportStreamMultiplexor::doGetNextFrame() { - if (fInputBufferBytesUsed >= fInputBufferSize) { - // No more bytes are available from the current buffer. - // Arrange to read a new one. - awaitNewBuffer(fInputBuffer); - return; - } - - do { - // Periodically return a Program Association Table packet instead: - if (fOutgoingPacketCounter++ % PAT_FREQUENCY == 0) { - deliverPATPacket(); - break; - } - - // Periodically (or when we see a new PID) return a Program Map Table instead: - Boolean programMapHasChanged = fPIDState[fCurrentPID].counter == 0 - || fCurrentInputProgramMapVersion != fPreviousInputProgramMapVersion; - if (fOutgoingPacketCounter % PMT_FREQUENCY == 0 || programMapHasChanged) { - if (programMapHasChanged) { // reset values for next time: - fPIDState[fCurrentPID].counter = 1; - fPreviousInputProgramMapVersion = fCurrentInputProgramMapVersion; - } - deliverPMTPacket(programMapHasChanged); - break; - } - - // Normal case: Deliver (or continue delivering) the recently-read data: - deliverDataToClient(fCurrentPID, fInputBuffer, fInputBufferSize, - fInputBufferBytesUsed); - } while (0); - - // NEED TO SET fPresentationTime, durationInMicroseconds ##### - // Complete the delivery to the client: - afterGetting(this); -} - -void MPEG2TransportStreamMultiplexor -::handleNewBuffer(unsigned char* buffer, unsigned bufferSize, - int mpegVersion, MPEG1or2Demux::SCR scr) { - if (bufferSize < 4) return; - fInputBuffer = buffer; - fInputBufferSize = bufferSize; - fInputBufferBytesUsed = 0; - - u_int8_t stream_id = fInputBuffer[3]; - // Use "stream_id" directly as our PID. - // Also, figure out the Program Map 'stream type' from this. - if (stream_id == 0xBE) { // padding_stream; ignore - fInputBufferSize = 0; - } else if (stream_id == 0xBC) { // program_stream_map - setProgramStreamMap(fInputBufferSize); - fInputBufferSize = 0; // then, ignore the buffer - } else { - fCurrentPID = stream_id; - - // Set the stream's type: - u_int8_t& streamType = fPIDState[fCurrentPID].streamType; // alias - - if (streamType == 0) { - // Instead, set the stream's type to default values, based on whether - // the stream is audio or video, and whether it's MPEG-1 or MPEG-2: - if ((stream_id&0xF0) == 0xE0) { // video - streamType = mpegVersion == 1 ? 1 : 2; - if (fPCR_PID == 0) fPCR_PID = fCurrentPID; // use this stream's SCR for PCR - } else if ((stream_id&0xE0) == 0xC0) { // audio - streamType = mpegVersion == 1 ? 3 : 4; - if (!fHaveVideoStreams && fPCR_PID == 0) fPCR_PID = fCurrentPID; // use this stream's SCR for PCR - } else if (stream_id == 0xBD) { // private_stream1 (usually AC-3) - streamType = 0x06; // for DVB; for ATSC, use 0x81 - } else { // something else, e.g., AC-3 uses private_stream1 (0xBD) - streamType = 0x81; // private - } - } - - if (fCurrentPID == fPCR_PID) { - // Record the input's current SCR timestamp, for use as our PCR: - fPCR = scr; - } - } - - // Now that we have new input data, retry the last delivery to the client: - doGetNextFrame(); -} - -void MPEG2TransportStreamMultiplexor -::deliverDataToClient(u_int8_t pid, unsigned char* buffer, unsigned bufferSize, - unsigned& startPositionInBuffer) { - // Construct a new Transport packet, and deliver it to the client: - if (fMaxSize < TRANSPORT_PACKET_SIZE) { - fFrameSize = 0; // the client hasn't given us enough space; deliver nothing - fNumTruncatedBytes = TRANSPORT_PACKET_SIZE; - } else { - fFrameSize = TRANSPORT_PACKET_SIZE; - Boolean willAddPCR = pid == fPCR_PID && startPositionInBuffer == 0 - && !(fPCR.highBit == 0 && fPCR.remainingBits == 0 && fPCR.extension == 0); - unsigned const numBytesAvailable = bufferSize - startPositionInBuffer; - unsigned numHeaderBytes = 4; // by default - unsigned numPCRBytes = 0; // by default - unsigned numPaddingBytes = 0; // by default - unsigned numDataBytes; - u_int8_t adaptation_field_control; - if (willAddPCR) { - adaptation_field_control = 0x30; - numHeaderBytes += 2; // for the "adaptation_field_length" and flags - numPCRBytes = 6; - if (numBytesAvailable >= TRANSPORT_PACKET_SIZE - numHeaderBytes - numPCRBytes) { - numDataBytes = TRANSPORT_PACKET_SIZE - numHeaderBytes - numPCRBytes; - } else { - numDataBytes = numBytesAvailable; - numPaddingBytes - = TRANSPORT_PACKET_SIZE - numHeaderBytes - numPCRBytes - numDataBytes; - } - } else if (numBytesAvailable >= TRANSPORT_PACKET_SIZE - numHeaderBytes) { - // This is the common case - adaptation_field_control = 0x10; - numDataBytes = TRANSPORT_PACKET_SIZE - numHeaderBytes; - } else { - adaptation_field_control = 0x30; - ++numHeaderBytes; // for the "adaptation_field_length" - // ASSERT: numBytesAvailable <= TRANSPORT_PACKET_SIZE - numHeaderBytes - numDataBytes = numBytesAvailable; - if (numDataBytes < TRANSPORT_PACKET_SIZE - numHeaderBytes) { - ++numHeaderBytes; // for the adaptation field flags - numPaddingBytes = TRANSPORT_PACKET_SIZE - numHeaderBytes - numDataBytes; - } - } - // ASSERT: numHeaderBytes+numPCRBytes+numPaddingBytes+numDataBytes - // == TRANSPORT_PACKET_SIZE - - // Fill in the header of the Transport Stream packet: - unsigned char* header = fTo; - *header++ = 0x47; // sync_byte - *header++ = (startPositionInBuffer == 0) ? 0x40 : 0x00; - // transport_error_indicator, payload_unit_start_indicator, transport_priority, - // first 5 bits of PID - *header++ = pid; - // last 8 bits of PID - unsigned& continuity_counter = fPIDState[pid].counter; // alias - *header++ = adaptation_field_control|(continuity_counter&0x0F); - // transport_scrambling_control, adaptation_field_control, continuity_counter - ++continuity_counter; - if (adaptation_field_control == 0x30) { - // Add an adaptation field: - u_int8_t adaptation_field_length - = (numHeaderBytes == 5) ? 0 : 1 + numPCRBytes + numPaddingBytes; - *header++ = adaptation_field_length; - if (numHeaderBytes > 5) { - *header++ = willAddPCR ? 0x10 : 0x00; // various flags - if (willAddPCR) { - u_int32_t pcrHigh32Bits = (fPCR.highBit<<31) | (fPCR.remainingBits>>1); - u_int8_t pcrLowBit = fPCR.remainingBits&1; - u_int8_t extHighBit = (fPCR.extension&0x100)>>8; - *header++ = pcrHigh32Bits>>24; - *header++ = pcrHigh32Bits>>16; - *header++ = pcrHigh32Bits>>8; - *header++ = pcrHigh32Bits; - *header++ = (pcrLowBit<<7)|0x7E|extHighBit; - *header++ = (u_int8_t)fPCR.extension; // low 8 bits of extension - } - } - } - - // Add any padding bytes: - for (unsigned i = 0; i < numPaddingBytes; ++i) *header++ = 0xFF; - - // Finally, add the data bytes: - memmove(header, &buffer[startPositionInBuffer], numDataBytes); - startPositionInBuffer += numDataBytes; - } -} - -static u_int32_t calculateCRC(u_int8_t* data, unsigned dataLength); // forward - -#define PAT_PID 0 -#define OUR_PROGRAM_NUMBER 1 -#define OUR_PROGRAM_MAP_PID 0x10 - -void MPEG2TransportStreamMultiplexor::deliverPATPacket() { - // First, create a new buffer for the PAT packet: - unsigned const patSize = TRANSPORT_PACKET_SIZE - 4; // allow for the 4-byte header - unsigned char* patBuffer = new unsigned char[patSize]; - - // and fill it in: - unsigned char* pat = patBuffer; - *pat++ = 0; // pointer_field - *pat++ = 0; // table_id - *pat++ = 0xB0; // section_syntax_indicator; 0; reserved, section_length (high) - *pat++ = 13; // section_length (low) - *pat++ = 0; *pat++ = 1; // transport_stream_id - *pat++ = 0xC3; // reserved; version_number; current_next_indicator - *pat++ = 0; // section_number - *pat++ = 0; // last_section_number - *pat++ = OUR_PROGRAM_NUMBER>>8; *pat++ = OUR_PROGRAM_NUMBER; // program_number - *pat++ = 0xE0|(OUR_PROGRAM_MAP_PID>>8); // reserved; program_map_PID (high) - *pat++ = OUR_PROGRAM_MAP_PID; // program_map_PID (low) - - // Compute the CRC from the bytes we currently have (not including "pointer_field"): - u_int32_t crc = calculateCRC(patBuffer+1, pat - (patBuffer+1)); - *pat++ = crc>>24; *pat++ = crc>>16; *pat++ = crc>>8; *pat++ = crc; - - // Fill in the rest of the packet with padding bytes: - while (pat < &patBuffer[patSize]) *pat++ = 0xFF; - - // Deliver the packet: - unsigned startPosition = 0; - deliverDataToClient(PAT_PID, patBuffer, patSize, startPosition); - - // Finally, remove the new buffer: - delete[] patBuffer; -} - -void MPEG2TransportStreamMultiplexor::deliverPMTPacket(Boolean hasChanged) { - if (hasChanged) ++fProgramMapVersion; - - // First, create a new buffer for the PMT packet: - unsigned const pmtSize = TRANSPORT_PACKET_SIZE - 4; // allow for the 4-byte header - unsigned char* pmtBuffer = new unsigned char[pmtSize]; - - // and fill it in: - unsigned char* pmt = pmtBuffer; - *pmt++ = 0; // pointer_field - *pmt++ = 2; // table_id - *pmt++ = 0xB0; // section_syntax_indicator; 0; reserved, section_length (high) - unsigned char* section_lengthPtr = pmt; // save for later - *pmt++ = 0; // section_length (low) (fill in later) - *pmt++ = OUR_PROGRAM_NUMBER>>8; *pmt++ = OUR_PROGRAM_NUMBER; // program_number - *pmt++ = 0xC1|((fProgramMapVersion&0x1F)<<1); // reserved; version_number; current_next_indicator - *pmt++ = 0; // section_number - *pmt++ = 0; // last_section_number - *pmt++ = 0xE0; // reserved; PCR_PID (high) - *pmt++ = fPCR_PID; // PCR_PID (low) - *pmt++ = 0xF0; // reserved; program_info_length (high) - *pmt++ = 0; // program_info_length (low) - for (int pid = 0; pid < PID_TABLE_SIZE; ++pid) { - if (fPIDState[pid].streamType != 0) { - // This PID gets recorded in the table - *pmt++ = fPIDState[pid].streamType; - *pmt++ = 0xE0; // reserved; elementary_pid (high) - *pmt++ = pid; // elementary_pid (low) - *pmt++ = 0xF0; // reserved; ES_info_length (high) - *pmt++ = 0; // ES_info_length (low) - } - } - unsigned section_length = pmt - (section_lengthPtr+1) + 4 /*for CRC*/; - *section_lengthPtr = section_length; - - // Compute the CRC from the bytes we currently have (not including "pointer_field"): - u_int32_t crc = calculateCRC(pmtBuffer+1, pmt - (pmtBuffer+1)); - *pmt++ = crc>>24; *pmt++ = crc>>16; *pmt++ = crc>>8; *pmt++ = crc; - - // Fill in the rest of the packet with padding bytes: - while (pmt < &pmtBuffer[pmtSize]) *pmt++ = 0xFF; - - // Deliver the packet: - unsigned startPosition = 0; - deliverDataToClient(OUR_PROGRAM_MAP_PID, pmtBuffer, pmtSize, startPosition); - - // Finally, remove the new buffer: - delete[] pmtBuffer; -} - -void MPEG2TransportStreamMultiplexor::setProgramStreamMap(unsigned frameSize) { - if (frameSize <= 16) return; // program_stream_map is too small to be useful - if (frameSize > 0xFF) return; // program_stream_map is too large - - u_int16_t program_stream_map_length = (fInputBuffer[4]<<8) | fInputBuffer[5]; - if ((u_int16_t)frameSize > 6+program_stream_map_length) { - frameSize = 6+program_stream_map_length; - } - - u_int8_t versionByte = fInputBuffer[6]; - if ((versionByte&0x80) == 0) return; // "current_next_indicator" is not set - fCurrentInputProgramMapVersion = versionByte&0x1F; - - u_int16_t program_stream_info_length = (fInputBuffer[8]<<8) | fInputBuffer[9]; - unsigned offset = 10 + program_stream_info_length; // skip over 'descriptors' - - u_int16_t elementary_stream_map_length - = (fInputBuffer[offset]<<8) | fInputBuffer[offset+1]; - offset += 2; - frameSize -= 4; // sizeof CRC_32 - if (frameSize > offset + elementary_stream_map_length) { - frameSize = offset + elementary_stream_map_length; - } - - while (offset + 4 <= frameSize) { - u_int8_t stream_type = fInputBuffer[offset]; - u_int8_t elementary_stream_id = fInputBuffer[offset+1]; - - fPIDState[elementary_stream_id].streamType = stream_type; - - u_int16_t elementary_stream_info_length - = (fInputBuffer[offset+2]<<8) | fInputBuffer[offset+3]; - offset += 4 + elementary_stream_info_length; - } -} - -static u_int32_t CRC32[256] = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, - 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, - 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, - 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, - 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, - 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, - 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, - 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, - 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, - 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, - 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, - 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, - 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, - 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, - 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, - 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, - 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, - 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, - 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, - 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, - 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, - 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, - 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, - 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, - 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, - 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, - 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, - 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, - 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, - 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, - 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, - 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, - 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, - 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, - 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, - 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, - 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, - 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, - 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, - 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, - 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, - 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, - 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 -}; - -static u_int32_t calculateCRC(u_int8_t* data, unsigned dataLength) { - u_int32_t crc = 0xFFFFFFFF; - - while (dataLength-- > 0) { - crc = (crc<<8) ^ CRC32[(crc>>24) ^ (u_int32_t)(*data++)]; - } - - return crc; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4ESVideoRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4ESVideoRTPSink.cpp deleted file mode 100644 index 45b84962fb1..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4ESVideoRTPSink.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for MPEG-4 Elementary Stream video (RFC 3016) -// Implementation - -#include "MPEG4ESVideoRTPSink.hh" -#include "MPEG4VideoStreamFramer.hh" - -MPEG4ESVideoRTPSink -::MPEG4ESVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency) - : VideoRTPSink(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, "MP4V-ES"), - fVOPIsPresent(False), fAuxSDPLine(NULL) { -} - -MPEG4ESVideoRTPSink::~MPEG4ESVideoRTPSink() { - delete[] fAuxSDPLine; -} - -MPEG4ESVideoRTPSink* -MPEG4ESVideoRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency) { - return new MPEG4ESVideoRTPSink(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -Boolean MPEG4ESVideoRTPSink::sourceIsCompatibleWithUs(MediaSource& source) { - // Our source must be an appropriate framer: - return source.isMPEG4VideoStreamFramer(); -} - -#define VOP_START_CODE 0x000001B6 - -void MPEG4ESVideoRTPSink -::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - if (fragmentationOffset == 0) { - // Begin by inspecting the 4-byte code at the start of the frame: - if (numBytesInFrame < 4) return; // shouldn't happen - unsigned startCode = (frameStart[0]<<24) | (frameStart[1]<<16) - | (frameStart[2]<<8) | frameStart[3]; - - fVOPIsPresent = startCode == VOP_START_CODE; - } - - // Set the RTP 'M' (marker) bit iff this frame ends a VOP - // (and there are no fragments remaining). - // This relies on the source being a "MPEG4VideoStreamFramer". - MPEG4VideoStreamFramer* framerSource = (MPEG4VideoStreamFramer*)fSource; - if (framerSource != NULL && framerSource->pictureEndMarker() - && numRemainingBytes == 0) { - setMarkerBit(); - framerSource->pictureEndMarker() = False; - } - - // Also set the RTP timestamp. (We do this for each frame - // in the packet, to ensure that the timestamp of the VOP (if present) - // gets used.) - setTimestamp(frameTimestamp); -} - -Boolean MPEG4ESVideoRTPSink::allowFragmentationAfterStart() const { - return True; -} - -Boolean MPEG4ESVideoRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - // Once we've packed a VOP into the packet, then no other - // frame can be packed into it: - return !fVOPIsPresent; -} - -char const* MPEG4ESVideoRTPSink::auxSDPLine() { - // Generate a new "a=fmtp:" line each time, using parameters from - // our framer source (in case they've changed since the last time that - // we were called): - MPEG4VideoStreamFramer* framerSource = (MPEG4VideoStreamFramer*)fSource; - if (framerSource == NULL) return NULL; // we don't yet have a source - - u_int8_t profile_level_id = framerSource->profile_and_level_indication(); - if (profile_level_id == 0) return NULL; // our source isn't ready - - unsigned configLength; - unsigned char* config = framerSource->getConfigBytes(configLength); - if (config == NULL) return NULL; // our source isn't ready - - char const* fmtpFmt = - "a=fmtp:%d " - "profile-level-id=%d;" - "config="; - unsigned fmtpFmtSize = strlen(fmtpFmt) - + 3 /* max char len */ - + 3 /* max char len */ - + 2*configLength /* 2*, because each by prints as 2 chars */ - + 2 /* trailing \r\n */; - char* fmtp = new char[fmtpFmtSize]; - sprintf(fmtp, fmtpFmt, rtpPayloadType(), profile_level_id); - char* endPtr = &fmtp[strlen(fmtp)]; - for (unsigned i = 0; i < configLength; ++i) { - sprintf(endPtr, "%02X", config[i]); - endPtr += 2; - } - sprintf(endPtr, "\r\n"); - - delete[] fAuxSDPLine; - fAuxSDPLine = strDup(fmtp); - delete[] fmtp; - return fAuxSDPLine; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4ESVideoRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4ESVideoRTPSource.cpp deleted file mode 100644 index 37aace4dfec..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4ESVideoRTPSource.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP4V-ES video RTP stream sources -// Implementation - -#include "MPEG4ESVideoRTPSource.hh" - -///////// MPEG4ESVideoRTPSource implementation //////// - -//##### NOTE: INCOMPLETE!!! ##### - -MPEG4ESVideoRTPSource* -MPEG4ESVideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new MPEG4ESVideoRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -MPEG4ESVideoRTPSource -::MPEG4ESVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency) { -} - -MPEG4ESVideoRTPSource::~MPEG4ESVideoRTPSource() { -} - -Boolean MPEG4ESVideoRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - // The packet begins a frame iff its data begins with a system code - // (i.e., 0x000001??) - fCurrentPacketBeginsFrame - = packet->dataSize() >= 4 && (packet->data())[0] == 0 - && (packet->data())[1] == 0 && (packet->data())[2] == 1; - - // The RTP "M" (marker) bit indicates the last fragment of a frame: - fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); - - // There is no special header - resultSpecialHeaderSize = 0; - return True; -} - -char const* MPEG4ESVideoRTPSource::MIMEtype() const { - return "video/MP4V-ES"; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4GenericRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4GenericRTPSink.cpp deleted file mode 100644 index cd28e2f7056..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4GenericRTPSink.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG4-GENERIC ("audio", "video", or "application") RTP stream sinks -// Implementation - -#include "MPEG4GenericRTPSink.hh" - -MPEG4GenericRTPSink -::MPEG4GenericRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency, - char const* sdpMediaTypeString, - char const* mpeg4Mode, char const* configString, - unsigned numChannels) - : MultiFramedRTPSink(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, "MPEG4-GENERIC", numChannels), - fSDPMediaTypeString(strDup(sdpMediaTypeString)), - fMPEG4Mode(strDup(mpeg4Mode)), fConfigString(strDup(configString)) { - // Check whether "mpeg4Mode" is one that we handle: - if (mpeg4Mode == NULL) { - env << "MPEG4GenericRTPSink error: NULL \"mpeg4Mode\" parameter\n"; - } else if (strcmp(mpeg4Mode, "AAC-hbr") != 0) { - env << "MPEG4GenericRTPSink error: Unknown \"mpeg4Mode\" parameter: \"" - << mpeg4Mode << "\"\n"; - } - - // Set up the "a=fmtp:" SDP line for this stream: - char const* fmtpFmt = - "a=fmtp:%d " - "streamtype=%d;profile-level-id=1;" - "mode=%s;sizelength=13;indexlength=3;indexdeltalength=3;" - "config=%s\r\n"; - unsigned fmtpFmtSize = strlen(fmtpFmt) - + 3 /* max char len */ - + 3 /* max char len */ - + strlen(fMPEG4Mode) - + strlen(fConfigString); - char* fmtp = new char[fmtpFmtSize]; - sprintf(fmtp, fmtpFmt, - rtpPayloadType(), - strcmp(fSDPMediaTypeString, "video") == 0 ? 4 : 5, - fMPEG4Mode, - fConfigString); - fFmtpSDPLine = strDup(fmtp); - delete[] fmtp; -} - -MPEG4GenericRTPSink::~MPEG4GenericRTPSink() { - delete[] fFmtpSDPLine; - delete[] (char*)fConfigString; - delete[] (char*)fMPEG4Mode; - delete[] (char*)fSDPMediaTypeString; -} - -MPEG4GenericRTPSink* -MPEG4GenericRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency, - char const* sdpMediaTypeString, - char const* mpeg4Mode, - char const* configString, unsigned numChannels) { - return new MPEG4GenericRTPSink(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, - sdpMediaTypeString, mpeg4Mode, - configString, numChannels); -} - -Boolean MPEG4GenericRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - // (For now) allow at most 1 frame in a single packet: - return False; -} - -void MPEG4GenericRTPSink -::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - // Set the "AU Header Section". This is 4 bytes: 2 bytes for the - // initial "AU-headers-length" field, and 2 bytes for the first - // (and only) "AU Header": - unsigned fullFrameSize - = fragmentationOffset + numBytesInFrame + numRemainingBytes; - unsigned char headers[4]; - headers[0] = 0; headers[1] = 16 /* bits */; // AU-headers-length - headers[2] = fullFrameSize >> 5; headers[3] = (fullFrameSize&0x1F)<<3; - - setSpecialHeaderBytes(headers, sizeof headers); - - if (numRemainingBytes == 0) { - // This packet contains the last (or only) fragment of the frame. - // Set the RTP 'M' ('marker') bit: - setMarkerBit(); - } - - // Important: Also call our base class's doSpecialFrameHandling(), - // to set the packet's timestamp: - MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, - frameStart, numBytesInFrame, - frameTimestamp, - numRemainingBytes); -} - -unsigned MPEG4GenericRTPSink::specialHeaderSize() const { - return 2 + 2; -} - -char const* MPEG4GenericRTPSink::sdpMediaType() const { - return fSDPMediaTypeString; -} - -char const* MPEG4GenericRTPSink::auxSDPLine() { - return fFmtpSDPLine; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4GenericRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4GenericRTPSource.cpp deleted file mode 100644 index b9d26fc4363..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4GenericRTPSource.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG4-GENERIC ("audio", "video", or "application") RTP stream sources -// Implementation - -#include "MPEG4GenericRTPSource.hh" -#include "BitVector.hh" -#include "MPEG4LATMAudioRTPSource.hh" // for parseGeneralConfigStr() - -////////// MPEG4GenericBufferedPacket and MPEG4GenericBufferedPacketFactory - -class MPEG4GenericBufferedPacket: public BufferedPacket { -public: - MPEG4GenericBufferedPacket(MPEG4GenericRTPSource* ourSource); - virtual ~MPEG4GenericBufferedPacket(); - -private: // redefined virtual functions - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); -private: - MPEG4GenericRTPSource* fOurSource; -}; - -class MPEG4GenericBufferedPacketFactory: public BufferedPacketFactory { -private: // redefined virtual functions - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - - -////////// AUHeader ////////// -struct AUHeader { - unsigned size; - unsigned index; // indexDelta for the 2nd & subsequent headers -}; - - -///////// MPEG4GenericRTPSource implementation //////// - -//##### NOTE: INCOMPLETE!!! Support more modes, and interleaving ##### - -MPEG4GenericRTPSource* -MPEG4GenericRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mediumName, - char const* mode, - unsigned sizeLength, unsigned indexLength, - unsigned indexDeltaLength - ) { - return new MPEG4GenericRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, mediumName, - mode, sizeLength, indexLength, - indexDeltaLength - ); -} - -MPEG4GenericRTPSource -::MPEG4GenericRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mediumName, - char const* mode, - unsigned sizeLength, unsigned indexLength, - unsigned indexDeltaLength - ) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency, - new MPEG4GenericBufferedPacketFactory), - fSizeLength(sizeLength), fIndexLength(indexLength), - fIndexDeltaLength(indexDeltaLength), - fNumAUHeaders(0), fNextAUHeader(0), fAUHeaders(NULL) { - unsigned mimeTypeLength = - strlen(mediumName) + 14 /* strlen("/MPEG4-GENERIC") */ + 1; - fMIMEType = new char[mimeTypeLength]; - if (fMIMEType != NULL) { - sprintf(fMIMEType, "%s/MPEG4-GENERIC", mediumName); - } - - fMode = strDup(mode); - // Check for a "mode" that we don't yet support: //##### - if (mode == NULL || - (strcmp(mode, "aac-hbr") != 0 && strcmp(mode, "generic") != 0)) { - envir() << "MPEG4GenericRTPSource Warning: Unknown or unsupported \"mode\": " - << mode << "\n"; - } -} - -MPEG4GenericRTPSource::~MPEG4GenericRTPSource() { - delete[] fAUHeaders; - delete[] fMode; - delete[] fMIMEType; -} - -Boolean MPEG4GenericRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - unsigned char* headerStart = packet->data(); - unsigned packetSize = packet->dataSize(); - - fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame; - // whether the *previous* packet ended a frame - - // The RTP "M" (marker) bit indicates the last fragment of a frame: - fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); - - // default values: - resultSpecialHeaderSize = 0; - fNumAUHeaders = 0; - fNextAUHeader = 0; - delete[] fAUHeaders; fAUHeaders = NULL; - - if (fSizeLength > 0) { - // The packet begins with a "AU Header Section". Parse it, to - // determine the "AU-header"s for each frame present in this packet: - resultSpecialHeaderSize += 2; - if (packetSize < resultSpecialHeaderSize) return False; - - unsigned AU_headers_length = (headerStart[0]<<8)|headerStart[1]; - unsigned AU_headers_length_bytes = (AU_headers_length+7)/8; - if (packetSize - < resultSpecialHeaderSize + AU_headers_length_bytes) return False; - resultSpecialHeaderSize += AU_headers_length_bytes; - - // Figure out how many AU-headers are present in the packet: - int bitsAvail = AU_headers_length - (fSizeLength + fIndexLength); - if (bitsAvail >= 0 && (fSizeLength + fIndexDeltaLength) > 0) { - fNumAUHeaders = 1 + bitsAvail/(fSizeLength + fIndexDeltaLength); - } - if (fNumAUHeaders > 0) { - fAUHeaders = new AUHeader[fNumAUHeaders]; - // Fill in each header: - BitVector bv(&headerStart[2], 0, AU_headers_length); - fAUHeaders[0].size = bv.getBits(fSizeLength); - fAUHeaders[0].index = bv.getBits(fIndexLength); - - for (unsigned i = 1; i < fNumAUHeaders; ++i) { - fAUHeaders[i].size = bv.getBits(fSizeLength); - fAUHeaders[i].index = bv.getBits(fIndexDeltaLength); - } - } - - } - - return True; -} - -char const* MPEG4GenericRTPSource::MIMEtype() const { - return fMIMEType; -} - - -////////// MPEG4GenericBufferedPacket -////////// and MPEG4GenericBufferedPacketFactory implementation - -MPEG4GenericBufferedPacket -::MPEG4GenericBufferedPacket(MPEG4GenericRTPSource* ourSource) - : fOurSource(ourSource) { -} - -MPEG4GenericBufferedPacket::~MPEG4GenericBufferedPacket() { -} - -unsigned MPEG4GenericBufferedPacket -::nextEnclosedFrameSize(unsigned char*& /*framePtr*/, unsigned dataSize) { - // WE CURRENTLY DON'T IMPLEMENT INTERLEAVING. FIX THIS! ##### - AUHeader* auHeader = fOurSource->fAUHeaders; - if (auHeader == NULL) return dataSize; - unsigned numAUHeaders = fOurSource->fNumAUHeaders; - - if (fOurSource->fNextAUHeader >= numAUHeaders) { - fOurSource->envir() << "MPEG4GenericBufferedPacket::nextEnclosedFrameSize(" - << dataSize << "): data error (" - << auHeader << "," << fOurSource->fNextAUHeader - << "," << numAUHeaders << ")!\n"; - return dataSize; - } - - auHeader = &auHeader[fOurSource->fNextAUHeader++]; - return auHeader->size <= dataSize ? auHeader->size : dataSize; -} - -BufferedPacket* MPEG4GenericBufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* ourSource) { - return new MPEG4GenericBufferedPacket((MPEG4GenericRTPSource*)ourSource); -} - - -////////// samplingFrequencyFromAudioSpecificConfig() implementation ////////// - -static unsigned samplingFrequencyFromIndex[16] = { - 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, - 16000, 12000, 11025, 8000, 7350, 0, 0, 0 -}; - -unsigned samplingFrequencyFromAudioSpecificConfig(char const* configStr) { - unsigned char* config = NULL; - unsigned result = 0; // if returned, indicates an error - - do { - // Begin by parsing the config string: - unsigned configSize; - config = parseGeneralConfigStr(configStr, configSize); - if (config == NULL) break; - - if (configSize < 2) break; - unsigned char samplingFrequencyIndex = ((config[0]&0x07)<<1) | (config[1]>>7); - if (samplingFrequencyIndex < 15) { - result = samplingFrequencyFromIndex[samplingFrequencyIndex]; - break; - } - - // Index == 15 means that the actual frequency is next (24 bits): - if (configSize < 5) break; - result = ((config[1]&0x7F)<<17) | (config[2]<<9) | (config[3]<<1) | (config[4]>>7); - } while (0); - - delete[] config; - return result; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4LATMAudioRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4LATMAudioRTPSink.cpp deleted file mode 100644 index 0cc6272c916..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4LATMAudioRTPSink.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for MPEG-4 audio, using LATM multiplexing (RFC 3016) -// Implementation - -#include "MPEG4LATMAudioRTPSink.hh" - -MPEG4LATMAudioRTPSink -::MPEG4LATMAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency, - char const* streamMuxConfigString, - unsigned numChannels, - Boolean allowMultipleFramesPerPacket) - : AudioRTPSink(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, "MP4A-LATM", numChannels), - fStreamMuxConfigString(strDup(streamMuxConfigString)), - fAllowMultipleFramesPerPacket(allowMultipleFramesPerPacket) { - // Set up the "a=fmtp:" SDP line for this stream: - char const* fmtpFmt = - "a=fmtp:%d " - "cpresent=0;config=%s\r\n"; - unsigned fmtpFmtSize = strlen(fmtpFmt) - + 3 /* max char len */ - + strlen(fStreamMuxConfigString); - char* fmtp = new char[fmtpFmtSize]; - sprintf(fmtp, fmtpFmt, - rtpPayloadType(), - fStreamMuxConfigString); - fFmtpSDPLine = strDup(fmtp); - delete[] fmtp; -} - -MPEG4LATMAudioRTPSink::~MPEG4LATMAudioRTPSink() { - delete[] fFmtpSDPLine; - delete[] (char*)fStreamMuxConfigString; -} - -MPEG4LATMAudioRTPSink* -MPEG4LATMAudioRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency, - char const* streamMuxConfigString, - unsigned numChannels, - Boolean allowMultipleFramesPerPacket) { - return new MPEG4LATMAudioRTPSink(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, streamMuxConfigString, - numChannels, - allowMultipleFramesPerPacket); -} - -Boolean MPEG4LATMAudioRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - return fAllowMultipleFramesPerPacket; -} - -void MPEG4LATMAudioRTPSink -::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - if (numRemainingBytes == 0) { - // This packet contains the last (or only) fragment of the frame. - // Set the RTP 'M' ('marker') bit: - setMarkerBit(); - } - - // Important: Also call our base class's doSpecialFrameHandling(), - // to set the packet's timestamp: - MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, - frameStart, numBytesInFrame, - frameTimestamp, - numRemainingBytes); -} - -char const* MPEG4LATMAudioRTPSink::auxSDPLine() { - return fFmtpSDPLine; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4LATMAudioRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4LATMAudioRTPSource.cpp deleted file mode 100644 index c22e6730f42..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4LATMAudioRTPSource.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG-4 audio, using LATM multiplexing -// Implementation - -#include "MPEG4LATMAudioRTPSource.hh" - -////////// LATMBufferedPacket and LATMBufferedPacketFactory ////////// - -class LATMBufferedPacket: public BufferedPacket { -public: - LATMBufferedPacket(Boolean includeLATMDataLengthField); - virtual ~LATMBufferedPacket(); - -private: // redefined virtual functions - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); - -private: - Boolean fIncludeLATMDataLengthField; -}; - -class LATMBufferedPacketFactory: public BufferedPacketFactory { -private: // redefined virtual functions - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - -///////// MPEG4LATMAudioRTPSource implementation //////// - -MPEG4LATMAudioRTPSource* -MPEG4LATMAudioRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new MPEG4LATMAudioRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -MPEG4LATMAudioRTPSource -::MPEG4LATMAudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency, - new LATMBufferedPacketFactory), - fIncludeLATMDataLengthField(True) { -} - -MPEG4LATMAudioRTPSource::~MPEG4LATMAudioRTPSource() { -} - -void MPEG4LATMAudioRTPSource::omitLATMDataLengthField() { - fIncludeLATMDataLengthField = False; -} - -Boolean MPEG4LATMAudioRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame; - // whether the *previous* packet ended a frame - - // The RTP "M" (marker) bit indicates the last fragment of a frame: - fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); - - // There is no special header - resultSpecialHeaderSize = 0; - return True; -} - -char const* MPEG4LATMAudioRTPSource::MIMEtype() const { - return "audio/MP4A-LATM"; -} - - -////////// LATMBufferedPacket and LATMBufferedPacketFactory implementation - -LATMBufferedPacket::LATMBufferedPacket(Boolean includeLATMDataLengthField) - : fIncludeLATMDataLengthField(includeLATMDataLengthField) { -} - -LATMBufferedPacket::~LATMBufferedPacket() { -} - -unsigned LATMBufferedPacket -::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { - // Look at the LATM data length byte(s), to determine the size - // of the LATM payload. - unsigned resultFrameSize = 0; - unsigned i; - for (i = 0; i < dataSize; ++i) { - resultFrameSize += framePtr[i]; - if (framePtr[i] != 0xFF) break; - } - ++i; - if (fIncludeLATMDataLengthField) { - resultFrameSize += i; - } else { - framePtr += i; - dataSize -= i; - } - - return (resultFrameSize <= dataSize) ? resultFrameSize : dataSize; -} - -BufferedPacket* LATMBufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* ourSource) { - MPEG4LATMAudioRTPSource* source = (MPEG4LATMAudioRTPSource*)ourSource; - return new LATMBufferedPacket(source->returnedFrameIncludesLATMDataLengthField()); -} - - -////////// parseStreamMuxConfigStr() implementation ////////// - -static Boolean getNibble(char const*& configStr, - unsigned char& resultNibble) { - char c = configStr[0]; - if (c == '\0') return False; // we've reached the end - - if (c >= '0' && c <= '9') { - resultNibble = c - '0'; - } else if (c >= 'A' && c <= 'F') { - resultNibble = 10 + c - 'A'; - } else if (c >= 'a' && c <= 'f') { - resultNibble = 10 + c - 'a'; - } else { - return False; - } - - ++configStr; // move to the next nibble - return True; -} - -static Boolean getByte(char const*& configStr, unsigned char& resultByte) { - unsigned char firstNibble; - if (!getNibble(configStr, firstNibble)) return False; - - unsigned char secondNibble = 0; - if (!getNibble(configStr, secondNibble) && configStr[0] != '\0') { - // There's a second nibble, but it's malformed - return False; - } - - resultByte = (firstNibble<<4)|secondNibble; - return True; -} - -Boolean -parseStreamMuxConfigStr(char const* configStr, - // result parameters: - Boolean& audioMuxVersion, - Boolean& allStreamsSameTimeFraming, - unsigned char& numSubFrames, - unsigned char& numProgram, - unsigned char& numLayer, - unsigned char*& audioSpecificConfig, - unsigned& audioSpecificConfigSize) { - // Set default versions of the result parameters: - audioMuxVersion = 0; - allStreamsSameTimeFraming = 1; - numSubFrames = numProgram = numLayer = 0; - audioSpecificConfig = NULL; - audioSpecificConfigSize = 0; - - do { - if (configStr == NULL) break; - - unsigned char nextByte; - - if (!getByte(configStr, nextByte)) break; - audioMuxVersion = (nextByte&0x80)>>7; - if (audioMuxVersion != 0) break; - - allStreamsSameTimeFraming = (nextByte&0x40)>>6; - numSubFrames = (nextByte&0x3F); - - if (!getByte(configStr, nextByte)) break; - numProgram = (nextByte&0xF0)>>4; - - numLayer = (nextByte&0x0E)>>1; - - // The one remaining bit, and the rest of the string, - // are used for "audioSpecificConfig": - unsigned char remainingBit = nextByte&1; - - unsigned ascSize = (strlen(configStr)+1)/2 + 1; - audioSpecificConfig = new unsigned char[ascSize]; - - Boolean parseSuccess; - unsigned i = 0; - do { - nextByte = 0; - parseSuccess = getByte(configStr, nextByte); - audioSpecificConfig[i++] = (remainingBit<<7)|((nextByte&0xFE)>>1); - remainingBit = nextByte&1; - } while (parseSuccess); - if (i != ascSize) break; // part of the remaining string was bad - - audioSpecificConfigSize = ascSize; - return True; // parsing succeeded - } while (0); - - delete[] audioSpecificConfig; - return False; // parsing failed -} - -unsigned char* parseStreamMuxConfigStr(char const* configStr, - // result parameter: - unsigned& audioSpecificConfigSize) { - Boolean audioMuxVersion, allStreamsSameTimeFraming; - unsigned char numSubFrames, numProgram, numLayer; - unsigned char* audioSpecificConfig; - - if (!parseStreamMuxConfigStr(configStr, - audioMuxVersion, allStreamsSameTimeFraming, - numSubFrames, numProgram, numLayer, - audioSpecificConfig, audioSpecificConfigSize)) { - audioSpecificConfigSize = 0; - return NULL; - } - - return audioSpecificConfig; -} - -unsigned char* parseGeneralConfigStr(char const* configStr, - // result parameter: - unsigned& configSize) { - unsigned char* config = NULL; - do { - if (configStr == NULL) break; - configSize = (strlen(configStr)+1)/2 + 1; - - config = new unsigned char[configSize]; - if (config == NULL) break; - - Boolean parseSuccess; - unsigned i = 0; - do { - parseSuccess = getByte(configStr, config[i++]); - } while (parseSuccess); - if (i != configSize) break; - // part of the remaining string was bad - - return config; - } while (0); - - configSize = 0; - delete[] config; - return NULL; -} - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoFileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoFileServerMediaSubsession.cpp deleted file mode 100644 index b5e2c81e1c6..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoFileServerMediaSubsession.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-4 video file. -// Implementation - -#include "MPEG4VideoFileServerMediaSubsession.hh" -#include "MPEG4ESVideoRTPSink.hh" -#include "ByteStreamFileSource.hh" -#include "MPEG4VideoStreamFramer.hh" - -MPEG4VideoFileServerMediaSubsession* -MPEG4VideoFileServerMediaSubsession::createNew(UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource) { - return new MPEG4VideoFileServerMediaSubsession(env, fileName, reuseFirstSource); -} - -MPEG4VideoFileServerMediaSubsession -::MPEG4VideoFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource) - : FileServerMediaSubsession(env, fileName, reuseFirstSource), - fDoneFlag(0) { -} - -MPEG4VideoFileServerMediaSubsession -::~MPEG4VideoFileServerMediaSubsession() { -} - -static void afterPlayingDummy(void* clientData) { - MPEG4VideoFileServerMediaSubsession* subsess - = (MPEG4VideoFileServerMediaSubsession*)clientData; - subsess->afterPlayingDummy1(); -} - -void MPEG4VideoFileServerMediaSubsession::afterPlayingDummy1() { - // Unschedule any pending 'checking' task: - envir().taskScheduler().unscheduleDelayedTask(nextTask()); - // Signal the event loop that we're done: - setDoneFlag(); -} - -static void checkForAuxSDPLine(void* clientData) { - MPEG4VideoFileServerMediaSubsession* subsess - = (MPEG4VideoFileServerMediaSubsession*)clientData; - subsess->checkForAuxSDPLine1(); -} - -void MPEG4VideoFileServerMediaSubsession::checkForAuxSDPLine1() { - if (fDummyRTPSink->auxSDPLine() != NULL) { - // Signal the event loop that we're done: - setDoneFlag(); - } else { - // try again after a brief delay: - int uSecsToDelay = 100000; // 100 ms - nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecsToDelay, - (TaskFunc*)checkForAuxSDPLine, this); - } -} - -char const* MPEG4VideoFileServerMediaSubsession -::getAuxSDPLine(RTPSink* rtpSink, FramedSource* inputSource) { - // Note: For MPEG-4 video files, the 'config' information isn't known - // until we start reading the file. This means that "rtpSink"s - // "auxSDPLine()" will be NULL initially, and we need to start reading - // data from our file until this changes. - fDummyRTPSink = rtpSink; - - // Start reading the file: - fDummyRTPSink->startPlaying(*inputSource, afterPlayingDummy, this); - - // Check whether the sink's 'auxSDPLine()' is ready: - checkForAuxSDPLine(this); - - envir().taskScheduler().doEventLoop(&fDoneFlag); - - char const* auxSDPLine = fDummyRTPSink->auxSDPLine(); - return auxSDPLine; -} - -FramedSource* MPEG4VideoFileServerMediaSubsession -::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) { - estBitrate = 500; // kbps, estimate - - // Create the video source: - ByteStreamFileSource* fileSource - = ByteStreamFileSource::createNew(envir(), fFileName); - if (fileSource == NULL) return NULL; - fFileSize = fileSource->fileSize(); - - // Create a framer for the Video Elementary Stream: - return MPEG4VideoStreamFramer::createNew(envir(), fileSource); -} - -RTPSink* MPEG4VideoFileServerMediaSubsession -::createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* /*inputSource*/) { - return MPEG4ESVideoRTPSink::createNew(envir(), rtpGroupsock, - rtpPayloadTypeIfDynamic); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoStreamDiscreteFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoStreamDiscreteFramer.cpp deleted file mode 100644 index 172e60632ae..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoStreamDiscreteFramer.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simplified version of "MPEG4VideoStreamFramer" that takes only complete, -// discrete frames (rather than an arbitrary byte stream) as input. -// This avoids the parsing and data copying overhead of the full -// "MPEG4VideoStreamFramer". -// Implementation - -#include "MPEG4VideoStreamDiscreteFramer.hh" - -MPEG4VideoStreamDiscreteFramer* -MPEG4VideoStreamDiscreteFramer::createNew(UsageEnvironment& env, - FramedSource* inputSource) { - // Need to add source type checking here??? ##### - return new MPEG4VideoStreamDiscreteFramer(env, inputSource); -} - -MPEG4VideoStreamDiscreteFramer -::MPEG4VideoStreamDiscreteFramer(UsageEnvironment& env, - FramedSource* inputSource) - : MPEG4VideoStreamFramer(env, inputSource, False/*don't create a parser*/), - vop_time_increment_resolution(0), fNumVTIRBits(0), - fLastNonBFrameVop_time_increment(0) { - fLastNonBFramePresentationTime.tv_sec = 0; - fLastNonBFramePresentationTime.tv_usec = 0; -} - -MPEG4VideoStreamDiscreteFramer::~MPEG4VideoStreamDiscreteFramer() { -} - -void MPEG4VideoStreamDiscreteFramer::doGetNextFrame() { - // Arrange to read data (which should be a complete MPEG-4 video frame) - // from our data source, directly into the client's input buffer. - // After reading this, we'll do some parsing on the frame. - fInputSource->getNextFrame(fTo, fMaxSize, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void MPEG4VideoStreamDiscreteFramer -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - MPEG4VideoStreamDiscreteFramer* source = (MPEG4VideoStreamDiscreteFramer*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -void MPEG4VideoStreamDiscreteFramer -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Check that the first 4 bytes are a system code: - if (frameSize >= 4 && fTo[0] == 0 && fTo[1] == 0 && fTo[2] == 1) { - fPictureEndMarker = True; // Assume that we have a complete 'picture' here - unsigned i = 3; - if (fTo[i] == 0xB0) { // VISUAL_OBJECT_SEQUENCE_START_CODE - // The next byte is the "profile_and_level_indication": - if (frameSize >= 5) fProfileAndLevelIndication = fTo[4]; - - // The start of this frame - up to the first GROUP_VOP_START_CODE - // or VOP_START_CODE - is stream configuration information. Save this: - for (i = 7; i < frameSize; ++i) { - if ((fTo[i] == 0xB3 /*GROUP_VOP_START_CODE*/ || - fTo[i] == 0xB6 /*VOP_START_CODE*/) - && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) { - break; // The configuration information ends here - } - } - fNumConfigBytes = i-3; - delete[] fConfigBytes; fConfigBytes = new unsigned char[fNumConfigBytes]; - for (unsigned j = 0; j < fNumConfigBytes; ++j) fConfigBytes[j] = fTo[j]; - - // This information (should) also contain a VOL header, which we need - // to analyze, to get "vop_time_increment_resolution" (which we need - // - along with "vop_time_increment" - in order to generate accurate - // presentation times for "B" frames). - analyzeVOLHeader(); - } - - if (i < frameSize) { - u_int8_t nextCode = fTo[i]; - - if (nextCode == 0xB3 /*GROUP_VOP_START_CODE*/) { - // Skip to the following VOP_START_CODE (if any): - for (i += 4; i < frameSize; ++i) { - if (fTo[i] == 0xB6 /*VOP_START_CODE*/ - && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) { - nextCode = fTo[i]; - break; - } - } - } - - if (nextCode == 0xB6 /*VOP_START_CODE*/ && i+5 < frameSize) { - ++i; - - // Get the "vop_coding_type" from the next byte: - u_int8_t nextByte = fTo[i++]; - u_int8_t vop_coding_type = nextByte>>6; - - // Next, get the "modulo_time_base" by counting the '1' bits that - // follow. We look at the next 32-bits only. - // This should be enough in most cases. - u_int32_t next4Bytes - = (fTo[i]<<24)|(fTo[i+1]<<16)|(fTo[i+2]<<8)|fTo[i+3]; - i += 4; - u_int32_t timeInfo = (nextByte<<(32-6))|(next4Bytes>>6); - unsigned modulo_time_base = 0; - u_int32_t mask = 0x80000000; - while ((timeInfo&mask) != 0) { - ++modulo_time_base; - mask >>= 1; - } - mask >>= 2; - - // Then, get the "vop_time_increment". - unsigned vop_time_increment = 0; - // First, make sure we have enough bits left for this: - if ((mask>>(fNumVTIRBits-1)) != 0) { - for (unsigned i = 0; i < fNumVTIRBits; ++i) { - vop_time_increment |= timeInfo&mask; - mask >>= 1; - } - while (mask != 0) { - vop_time_increment >>= 1; - mask >>= 1; - } - } - - // If this is a "B" frame, then we have to tweak "presentationTime": - if (vop_coding_type == 2/*B*/ - && (fLastNonBFramePresentationTime.tv_usec > 0 || - fLastNonBFramePresentationTime.tv_sec > 0)) { - int timeIncrement - = fLastNonBFrameVop_time_increment - vop_time_increment; - if (timeIncrement<0) timeIncrement += vop_time_increment_resolution; - unsigned const MILLION = 1000000; - double usIncrement = vop_time_increment_resolution == 0 ? 0.0 - : ((double)timeIncrement*MILLION)/vop_time_increment_resolution; - unsigned secondsToSubtract = (unsigned)(usIncrement/MILLION); - unsigned uSecondsToSubtract = ((unsigned)usIncrement)%MILLION; - - presentationTime = fLastNonBFramePresentationTime; - if ((unsigned)presentationTime.tv_usec < uSecondsToSubtract) { - presentationTime.tv_usec += MILLION; - if (presentationTime.tv_sec > 0) --presentationTime.tv_sec; - } - presentationTime.tv_usec -= uSecondsToSubtract; - if ((unsigned)presentationTime.tv_sec > secondsToSubtract) { - presentationTime.tv_sec -= secondsToSubtract; - } else { - presentationTime.tv_sec = presentationTime.tv_usec = 0; - } - } else { - fLastNonBFramePresentationTime = presentationTime; - fLastNonBFrameVop_time_increment = vop_time_increment; - } - } - } - } - - // Complete delivery to the client: - fFrameSize = frameSize; - fNumTruncatedBytes = numTruncatedBytes; - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - afterGetting(this); -} - -Boolean MPEG4VideoStreamDiscreteFramer::getNextFrameBit(u_int8_t& result) { - if (fNumBitsSeenSoFar/8 >= fNumConfigBytes) return False; - - u_int8_t nextByte = fConfigBytes[fNumBitsSeenSoFar/8]; - result = (nextByte>>(7-fNumBitsSeenSoFar%8))&1; - ++fNumBitsSeenSoFar; - return True; -} - -Boolean MPEG4VideoStreamDiscreteFramer::getNextFrameBits(unsigned numBits, - u_int32_t& result) { - result = 0; - for (unsigned i = 0; i < numBits; ++i) { - u_int8_t nextBit; - if (!getNextFrameBit(nextBit)) return False; - result = (result<<1)|nextBit; - } - return True; -} - -void MPEG4VideoStreamDiscreteFramer::analyzeVOLHeader() { - // Begin by moving to the VOL header: - unsigned i; - for (i = 3; i < fNumConfigBytes; ++i) { - if (fConfigBytes[i] >= 0x20 && fConfigBytes[i] <= 0x2F - && fConfigBytes[i-1] == 1 - && fConfigBytes[i-2] == 0 && fConfigBytes[i-3] == 0) { - ++i; - break; - } - } - - fNumBitsSeenSoFar = 8*i + 9; - do { - u_int8_t is_object_layer_identifier; - if (!getNextFrameBit(is_object_layer_identifier)) break; - if (is_object_layer_identifier) fNumBitsSeenSoFar += 7; - - u_int32_t aspect_ratio_info; - if (!getNextFrameBits(4, aspect_ratio_info)) break; - if (aspect_ratio_info == 15 /*extended_PAR*/) fNumBitsSeenSoFar += 16; - - u_int8_t vol_control_parameters; - if (!getNextFrameBit(vol_control_parameters)) break; - if (vol_control_parameters) { - fNumBitsSeenSoFar += 3; // chroma_format; low_delay - u_int8_t vbw_parameters; - if (!getNextFrameBit(vbw_parameters)) break; - if (vbw_parameters) fNumBitsSeenSoFar += 79; - } - - fNumBitsSeenSoFar += 2; // video_object_layer_shape - u_int8_t marker_bit; - if (!getNextFrameBit(marker_bit)) break; - if (marker_bit != 1) break; // sanity check - - if (!getNextFrameBits(16, vop_time_increment_resolution)) break; - if (vop_time_increment_resolution == 0) break; // shouldn't happen - - // Compute how many bits are necessary to represent this: - fNumVTIRBits = 0; - for (unsigned test = vop_time_increment_resolution; test>0; test /= 2) { - ++fNumVTIRBits; - } - } while (0); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoStreamFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoStreamFramer.cpp deleted file mode 100644 index c9d07c89006..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEG4VideoStreamFramer.cpp +++ /dev/null @@ -1,665 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an MPEG-4 video elementary stream into -// frames for: -// - Visual Object Sequence (VS) Header + Visual Object (VO) Header -// + Video Object Layer (VOL) Header -// - Group of VOP (GOV) Header -// - VOP frame -// Implementation - -#include "MPEG4VideoStreamFramer.hh" -#include "MPEGVideoStreamParser.hh" -#include - -////////// MPEG4VideoStreamParser definition ////////// - -// An enum representing the current state of the parser: -enum MPEGParseState { - PARSING_VISUAL_OBJECT_SEQUENCE, - PARSING_VISUAL_OBJECT_SEQUENCE_SEEN_CODE, - PARSING_VISUAL_OBJECT, - PARSING_VIDEO_OBJECT_LAYER, - PARSING_GROUP_OF_VIDEO_OBJECT_PLANE, - PARSING_VIDEO_OBJECT_PLANE, - PARSING_VISUAL_OBJECT_SEQUENCE_END_CODE -}; - -class MPEG4VideoStreamParser: public MPEGVideoStreamParser { -public: - MPEG4VideoStreamParser(MPEG4VideoStreamFramer* usingSource, - FramedSource* inputSource); - virtual ~MPEG4VideoStreamParser(); - -private: // redefined virtual functions: - virtual void flushInput(); - virtual unsigned parse(); - -private: - MPEG4VideoStreamFramer* usingSource() { - return (MPEG4VideoStreamFramer*)fUsingSource; - } - void setParseState(MPEGParseState parseState); - - unsigned parseVisualObjectSequence(Boolean haveSeenStartCode = False); - unsigned parseVisualObject(); - unsigned parseVideoObjectLayer(); - unsigned parseGroupOfVideoObjectPlane(); - unsigned parseVideoObjectPlane(); - unsigned parseVisualObjectSequenceEndCode(); - - // These are used for parsing within an already-read frame: - Boolean getNextFrameBit(u_int8_t& result); - Boolean getNextFrameBits(unsigned numBits, u_int32_t& result); - - // Which are used by: - void analyzeVOLHeader(); - -private: - MPEGParseState fCurrentParseState; - unsigned fNumBitsSeenSoFar; // used by the getNextFrameBit*() routines - u_int32_t vop_time_increment_resolution; - unsigned fNumVTIRBits; - // # of bits needed to count to "vop_time_increment_resolution" - u_int8_t fixed_vop_rate; - unsigned fixed_vop_time_increment; // used if 'fixed_vop_rate' is set - unsigned fSecondsSinceLastTimeCode, fTotalTicksSinceLastTimeCode, fPrevNewTotalTicks; - unsigned fPrevPictureCountDelta; - Boolean fJustSawTimeCode; -}; - - -////////// MPEG4VideoStreamFramer implementation ////////// - -MPEG4VideoStreamFramer* -MPEG4VideoStreamFramer::createNew(UsageEnvironment& env, - FramedSource* inputSource) { - // Need to add source type checking here??? ##### - return new MPEG4VideoStreamFramer(env, inputSource); -} - -unsigned char* MPEG4VideoStreamFramer -::getConfigBytes(unsigned& numBytes) const { - numBytes = fNumConfigBytes; - return fConfigBytes; -} - -MPEG4VideoStreamFramer::MPEG4VideoStreamFramer(UsageEnvironment& env, - FramedSource* inputSource, - Boolean createParser) - : MPEGVideoStreamFramer(env, inputSource), - fProfileAndLevelIndication(0), - fConfigBytes(NULL), fNumConfigBytes(0), - fNewConfigBytes(NULL), fNumNewConfigBytes(0) { - fParser = createParser - ? new MPEG4VideoStreamParser(this, inputSource) - : NULL; -} - -MPEG4VideoStreamFramer::~MPEG4VideoStreamFramer() { - delete[] fConfigBytes; delete[] fNewConfigBytes; -} - -void MPEG4VideoStreamFramer::startNewConfig() { - delete[] fNewConfigBytes; fNewConfigBytes = NULL; - fNumNewConfigBytes = 0; -} - -void MPEG4VideoStreamFramer -::appendToNewConfig(unsigned char* newConfigBytes, unsigned numNewBytes) { - // Allocate a new block of memory for the new config bytes: - unsigned char* configNew - = new unsigned char[fNumNewConfigBytes + numNewBytes]; - - // Copy the old, then the new, config bytes there: - memmove(configNew, fNewConfigBytes, fNumNewConfigBytes); - memmove(&configNew[fNumNewConfigBytes], newConfigBytes, numNewBytes); - - delete[] fNewConfigBytes; fNewConfigBytes = configNew; - fNumNewConfigBytes += numNewBytes; -} - -void MPEG4VideoStreamFramer::completeNewConfig() { - delete fConfigBytes; fConfigBytes = fNewConfigBytes; - fNewConfigBytes = NULL; - fNumConfigBytes = fNumNewConfigBytes; - fNumNewConfigBytes = 0; -} - -Boolean MPEG4VideoStreamFramer::isMPEG4VideoStreamFramer() const { - return True; -} - -////////// MPEG4VideoStreamParser implementation ////////// - -MPEG4VideoStreamParser -::MPEG4VideoStreamParser(MPEG4VideoStreamFramer* usingSource, - FramedSource* inputSource) - : MPEGVideoStreamParser(usingSource, inputSource), - fCurrentParseState(PARSING_VISUAL_OBJECT_SEQUENCE), - vop_time_increment_resolution(0), fNumVTIRBits(0), - fixed_vop_rate(0), fixed_vop_time_increment(0), - fSecondsSinceLastTimeCode(0), fTotalTicksSinceLastTimeCode(0), - fPrevNewTotalTicks(0), fPrevPictureCountDelta(1), fJustSawTimeCode(False) { -} - -MPEG4VideoStreamParser::~MPEG4VideoStreamParser() { -} - -void MPEG4VideoStreamParser::setParseState(MPEGParseState parseState) { - fCurrentParseState = parseState; - MPEGVideoStreamParser::setParseState(); -} - -void MPEG4VideoStreamParser::flushInput() { - fSecondsSinceLastTimeCode = 0; - fTotalTicksSinceLastTimeCode = 0; - fPrevNewTotalTicks = 0; - fPrevPictureCountDelta = 1; - - StreamParser::flushInput(); - if (fCurrentParseState != PARSING_VISUAL_OBJECT_SEQUENCE) { - setParseState(PARSING_VISUAL_OBJECT_SEQUENCE); // later, change to GOV or VOP? ##### - } -} - - -unsigned MPEG4VideoStreamParser::parse() { - try { - switch (fCurrentParseState) { - case PARSING_VISUAL_OBJECT_SEQUENCE: { - return parseVisualObjectSequence(); - } - case PARSING_VISUAL_OBJECT_SEQUENCE_SEEN_CODE: { - return parseVisualObjectSequence(True); - } - case PARSING_VISUAL_OBJECT: { - return parseVisualObject(); - } - case PARSING_VIDEO_OBJECT_LAYER: { - return parseVideoObjectLayer(); - } - case PARSING_GROUP_OF_VIDEO_OBJECT_PLANE: { - return parseGroupOfVideoObjectPlane(); - } - case PARSING_VIDEO_OBJECT_PLANE: { - return parseVideoObjectPlane(); - } - case PARSING_VISUAL_OBJECT_SEQUENCE_END_CODE: { - return parseVisualObjectSequenceEndCode(); - } - default: { - return 0; // shouldn't happen - } - } - } catch (int /*e*/) { -#ifdef DEBUG - fprintf(stderr, "MPEG4VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n"); -#endif - return 0; // the parsing got interrupted - } -} - -#define VISUAL_OBJECT_SEQUENCE_START_CODE 0x000001B0 -#define VISUAL_OBJECT_SEQUENCE_END_CODE 0x000001B1 -#define GROUP_VOP_START_CODE 0x000001B3 -#define VISUAL_OBJECT_START_CODE 0x000001B5 -#define VOP_START_CODE 0x000001B6 - -unsigned MPEG4VideoStreamParser -::parseVisualObjectSequence(Boolean haveSeenStartCode) { -#ifdef DEBUG - fprintf(stderr, "parsing VisualObjectSequence\n"); -#endif - usingSource()->startNewConfig(); - u_int32_t first4Bytes; - if (!haveSeenStartCode) { - while ((first4Bytes = test4Bytes()) != VISUAL_OBJECT_SEQUENCE_START_CODE) { -#ifdef DEBUG - fprintf(stderr, "ignoring non VS header: 0x%08x\n", first4Bytes); -#endif - get1Byte(); setParseState(PARSING_VISUAL_OBJECT_SEQUENCE); - // ensures we progress over bad data - } - first4Bytes = get4Bytes(); - } else { - // We've already seen the start code - first4Bytes = VISUAL_OBJECT_SEQUENCE_START_CODE; - } - save4Bytes(first4Bytes); - - // The next byte is the "profile_and_level_indication": - u_int8_t pali = get1Byte(); -#ifdef DEBUG - fprintf(stderr, "profile_and_level_indication: %02x\n", pali); -#endif - saveByte(pali); - usingSource()->fProfileAndLevelIndication = pali; - - // Now, copy all bytes that we see, up until we reach - // a VISUAL_OBJECT_START_CODE: - u_int32_t next4Bytes = get4Bytes(); - while (next4Bytes != VISUAL_OBJECT_START_CODE) { - saveToNextCode(next4Bytes); - } - - setParseState(PARSING_VISUAL_OBJECT); - - // Compute this frame's presentation time: - usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode); - - // This header forms part of the 'configuration' information: - usingSource()->appendToNewConfig(fStartOfFrame, curFrameSize()); - - return curFrameSize(); -} - -static inline Boolean isVideoObjectStartCode(u_int32_t code) { - return code >= 0x00000100 && code <= 0x0000011F; -} - -unsigned MPEG4VideoStreamParser::parseVisualObject() { -#ifdef DEBUG - fprintf(stderr, "parsing VisualObject\n"); -#endif - // Note that we've already read the VISUAL_OBJECT_START_CODE - save4Bytes(VISUAL_OBJECT_START_CODE); - - // Next, extract the "visual_object_type" from the next 1 or 2 bytes: - u_int8_t nextByte = get1Byte(); saveByte(nextByte); - Boolean is_visual_object_identifier = (nextByte&0x80) != 0; - u_int8_t visual_object_type; - if (is_visual_object_identifier) { -#ifdef DEBUG - fprintf(stderr, "visual_object_verid: 0x%x; visual_object_priority: 0x%x\n", (nextByte&0x78)>>3, (nextByte&0x07)); -#endif - nextByte = get1Byte(); saveByte(nextByte); - visual_object_type = (nextByte&0xF0)>>4; - } else { - visual_object_type = (nextByte&0x78)>>3; - } -#ifdef DEBUG - fprintf(stderr, "visual_object_type: 0x%x\n", visual_object_type); -#endif - // At present, we support only the "Video ID" "visual_object_type" (1) - if (visual_object_type != 1) { - usingSource()->envir() << "MPEG4VideoStreamParser::parseVisualObject(): Warning: We don't handle visual_object_type " << visual_object_type << "\n"; - } - - // Now, copy all bytes that we see, up until we reach - // a video_object_start_code - u_int32_t next4Bytes = get4Bytes(); - while (!isVideoObjectStartCode(next4Bytes)) { - saveToNextCode(next4Bytes); - } - save4Bytes(next4Bytes); -#ifdef DEBUG - fprintf(stderr, "saw a video_object_start_code: 0x%08x\n", next4Bytes); -#endif - - setParseState(PARSING_VIDEO_OBJECT_LAYER); - - // Compute this frame's presentation time: - usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode); - - // This header forms part of the 'configuration' information: - usingSource()->appendToNewConfig(fStartOfFrame, curFrameSize()); - - return curFrameSize(); -} - -static inline Boolean isVideoObjectLayerStartCode(u_int32_t code) { - return code >= 0x00000120 && code <= 0x0000012F; -} - -Boolean MPEG4VideoStreamParser::getNextFrameBit(u_int8_t& result) { - if (fNumBitsSeenSoFar/8 >= curFrameSize()) return False; - - u_int8_t nextByte = fStartOfFrame[fNumBitsSeenSoFar/8]; - result = (nextByte>>(7-fNumBitsSeenSoFar%8))&1; - ++fNumBitsSeenSoFar; - return True; -} - -Boolean MPEG4VideoStreamParser::getNextFrameBits(unsigned numBits, - u_int32_t& result) { - result = 0; - for (unsigned i = 0; i < numBits; ++i) { - u_int8_t nextBit; - if (!getNextFrameBit(nextBit)) return False; - result = (result<<1)|nextBit; - } - return True; -} - -void MPEG4VideoStreamParser::analyzeVOLHeader() { - // Extract timing information (in particular, - // "vop_time_increment_resolution") from the VOL Header: - fNumBitsSeenSoFar = 41; - do { - u_int8_t is_object_layer_identifier; - if (!getNextFrameBit(is_object_layer_identifier)) break; - if (is_object_layer_identifier) fNumBitsSeenSoFar += 7; - - u_int32_t aspect_ratio_info; - if (!getNextFrameBits(4, aspect_ratio_info)) break; - if (aspect_ratio_info == 15 /*extended_PAR*/) fNumBitsSeenSoFar += 16; - - u_int8_t vol_control_parameters; - if (!getNextFrameBit(vol_control_parameters)) break; - if (vol_control_parameters) { - fNumBitsSeenSoFar += 3; // chroma_format; low_delay - u_int8_t vbw_parameters; - if (!getNextFrameBit(vbw_parameters)) break; - if (vbw_parameters) fNumBitsSeenSoFar += 79; - } - - fNumBitsSeenSoFar += 2; // video_object_layer_shape - u_int8_t marker_bit; - if (!getNextFrameBit(marker_bit)) break; - if (marker_bit != 1) { // sanity check - usingSource()->envir() << "MPEG4VideoStreamParser::analyzeVOLHeader(): marker_bit 1 not set!\n"; - break; - } - - if (!getNextFrameBits(16, vop_time_increment_resolution)) break; -#ifdef DEBUG - fprintf(stderr, "vop_time_increment_resolution: %d\n", vop_time_increment_resolution); -#endif - if (vop_time_increment_resolution == 0) { - usingSource()->envir() << "MPEG4VideoStreamParser::analyzeVOLHeader(): vop_time_increment_resolution is zero!\n"; - break; - } - // Compute how many bits are necessary to represent this: - fNumVTIRBits = 0; - for (unsigned test = vop_time_increment_resolution; test>0; test /= 2) { - ++fNumVTIRBits; - } - - if (!getNextFrameBit(marker_bit)) break; - if (marker_bit != 1) { // sanity check - usingSource()->envir() << "MPEG4VideoStreamParser::analyzeVOLHeader(): marker_bit 2 not set!\n"; - break; - } - - if (!getNextFrameBit(fixed_vop_rate)) break; - if (fixed_vop_rate) { - // Get the following "fixed_vop_time_increment": - if (!getNextFrameBits(fNumVTIRBits, fixed_vop_time_increment)) break; -#ifdef DEBUG - fprintf(stderr, "fixed_vop_time_increment: %d\n", fixed_vop_time_increment); - if (fixed_vop_time_increment == 0) { - usingSource()->envir() << "MPEG4VideoStreamParser::analyzeVOLHeader(): fixed_vop_time_increment is zero!\n"; - } -#endif - } - // Use "vop_time_increment_resolution" as the 'frame rate' - // (really, 'tick rate'): - usingSource()->fFrameRate = (double)vop_time_increment_resolution; -#ifdef DEBUG - fprintf(stderr, "fixed_vop_rate: %d; 'frame' (really tick) rate: %f\n", fixed_vop_rate, usingSource()->fFrameRate); -#endif - - return; - } while (0); - - if (fNumBitsSeenSoFar/8 >= curFrameSize()) { - char errMsg[200]; - sprintf(errMsg, "Not enough bits in VOL header: %d/8 >= %d\n", fNumBitsSeenSoFar, curFrameSize()); - usingSource()->envir() << errMsg; - } -} - -unsigned MPEG4VideoStreamParser::parseVideoObjectLayer() { -#ifdef DEBUG - fprintf(stderr, "parsing VideoObjectLayer\n"); -#endif - // The first 4 bytes must be a "video_object_layer_start_code". - // If not, this is a 'short video header', which we currently - // don't support: - u_int32_t next4Bytes = get4Bytes(); - if (!isVideoObjectLayerStartCode(next4Bytes)) { - usingSource()->envir() << "MPEG4VideoStreamParser::parseVideoObjectLayer(): This appears to be a 'short video header', which we current don't support\n"; - } - - // Now, copy all bytes that we see, up until we reach - // a GROUP_VOP_START_CODE or a VOP_START_CODE: - do { - saveToNextCode(next4Bytes); - } while (next4Bytes != GROUP_VOP_START_CODE - && next4Bytes != VOP_START_CODE); - - analyzeVOLHeader(); - - setParseState((next4Bytes == GROUP_VOP_START_CODE) - ? PARSING_GROUP_OF_VIDEO_OBJECT_PLANE - : PARSING_VIDEO_OBJECT_PLANE); - - // Compute this frame's presentation time: - usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode); - - // This header ends the 'configuration' information: - usingSource()->appendToNewConfig(fStartOfFrame, curFrameSize()); - usingSource()->completeNewConfig(); - - return curFrameSize(); -} - -unsigned MPEG4VideoStreamParser::parseGroupOfVideoObjectPlane() { -#ifdef DEBUG - fprintf(stderr, "parsing GroupOfVideoObjectPlane\n"); -#endif - // Note that we've already read the GROUP_VOP_START_CODE - save4Bytes(GROUP_VOP_START_CODE); - - // Next, extract the (18-bit) time code from the next 3 bytes: - u_int8_t next3Bytes[3]; - getBytes(next3Bytes, 3); - saveByte(next3Bytes[0]);saveByte(next3Bytes[1]);saveByte(next3Bytes[2]); - unsigned time_code - = (next3Bytes[0]<<10)|(next3Bytes[1]<<2)|(next3Bytes[2]>>6); - unsigned time_code_hours = (time_code&0x0003E000)>>13; - unsigned time_code_minutes = (time_code&0x00001F80)>>7; -#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS) - Boolean marker_bit = (time_code&0x00000040) != 0; -#endif - unsigned time_code_seconds = (time_code&0x0000003F); -#if defined(DEBUG) || defined(DEBUG_TIMESTAMPS) - fprintf(stderr, "time_code: 0x%05x, hours %d, minutes %d, marker_bit %d, seconds %d\n", time_code, time_code_hours, time_code_minutes, marker_bit, time_code_seconds); -#endif - fJustSawTimeCode = True; - - // Now, copy all bytes that we see, up until we reach a VOP_START_CODE: - u_int32_t next4Bytes = get4Bytes(); - while (next4Bytes != VOP_START_CODE) { - saveToNextCode(next4Bytes); - } - - // Compute this frame's presentation time: - usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode); - - // Record the time code: - usingSource()->setTimeCode(time_code_hours, time_code_minutes, - time_code_seconds, 0, 0); - // Note: Because the GOV header can appear anywhere (not just at a 1s point), we - // don't pass "fTotalTicksSinceLastTimeCode" as the "picturesSinceLastGOP" parameter. - fSecondsSinceLastTimeCode = 0; - if (fixed_vop_rate) fTotalTicksSinceLastTimeCode = 0; - - setParseState(PARSING_VIDEO_OBJECT_PLANE); - - return curFrameSize(); -} - -unsigned MPEG4VideoStreamParser::parseVideoObjectPlane() { -#ifdef DEBUG - fprintf(stderr, "#parsing VideoObjectPlane\n"); -#endif - // Note that we've already read the VOP_START_CODE - save4Bytes(VOP_START_CODE); - - // Get the "vop_coding_type" from the next byte: - u_int8_t nextByte = get1Byte(); saveByte(nextByte); - u_int8_t vop_coding_type = nextByte>>6; - - // Next, get the "modulo_time_base" by counting the '1' bits that follow. - // We look at the next 32-bits only. This should be enough in most cases. - u_int32_t next4Bytes = get4Bytes(); - u_int32_t timeInfo = (nextByte<<(32-6))|(next4Bytes>>6); - unsigned modulo_time_base = 0; - u_int32_t mask = 0x80000000; - while ((timeInfo&mask) != 0) { - ++modulo_time_base; - mask >>= 1; - } - mask >>= 1; - - // Check the following marker bit: - if ((timeInfo&mask) == 0) { - usingSource()->envir() << "MPEG4VideoStreamParser::parseVideoObjectPlane(): marker bit not set!\n"; - } - mask >>= 1; - - // Then, get the "vop_time_increment". - // First, make sure we have enough bits left for this: - if ((mask>>(fNumVTIRBits-1)) == 0) { - usingSource()->envir() << "MPEG4VideoStreamParser::parseVideoObjectPlane(): 32-bits are not enough to get \"vop_time_increment\"!\n"; - } - unsigned vop_time_increment = 0; - for (unsigned i = 0; i < fNumVTIRBits; ++i) { - vop_time_increment |= timeInfo&mask; - mask >>= 1; - } - while (mask != 0) { - vop_time_increment >>= 1; - mask >>= 1; - } -#ifdef DEBUG - fprintf(stderr, "vop_coding_type: %d(%c), modulo_time_base: %d, vop_time_increment: %d\n", vop_coding_type, "IPBS"[vop_coding_type], modulo_time_base, vop_time_increment); -#endif - - // Now, copy all bytes that we see, up until we reach a code of some sort: - saveToNextCode(next4Bytes); - - // Update our counters based on the frame timing information that we saw: - if (fixed_vop_time_increment > 0) { - // This is a 'fixed_vop_rate' stream. Use 'fixed_vop_time_increment': - usingSource()->fPictureCount += fixed_vop_time_increment; - if (vop_time_increment > 0 || modulo_time_base > 0) { - fTotalTicksSinceLastTimeCode += fixed_vop_time_increment; - // Note: "fSecondsSinceLastTimeCode" and "fPrevNewTotalTicks" are not used. - } - } else { - // Use 'vop_time_increment': - unsigned newTotalTicks - = (fSecondsSinceLastTimeCode + modulo_time_base)*vop_time_increment_resolution - + vop_time_increment; - if (newTotalTicks == fPrevNewTotalTicks && fPrevNewTotalTicks > 0) { - // This is apparently a buggy MPEG-4 video stream, because - // "vop_time_increment" did not change. Overcome this error, - // by pretending that it did change. -#ifdef DEBUG - fprintf(stderr, "Buggy MPEG-4 video stream: \"vop_time_increment\" did not change!\n"); -#endif - // The following assumes that we don't have 'B' frames. If we do, then TARFU! - usingSource()->fPictureCount += vop_time_increment; - fTotalTicksSinceLastTimeCode += vop_time_increment; - fSecondsSinceLastTimeCode += modulo_time_base; - } else { - if (newTotalTicks < fPrevNewTotalTicks && vop_coding_type != 2/*B*/ - && modulo_time_base == 0 && vop_time_increment == 0 && !fJustSawTimeCode) { - // This is another kind of buggy MPEG-4 video stream, in which - // "vop_time_increment" wraps around, but without - // "modulo_time_base" changing (or just having had a new time code). - // Overcome this by pretending that "vop_time_increment" *did* wrap around: -#ifdef DEBUG - fprintf(stderr, "Buggy MPEG-4 video stream: \"vop_time_increment\" wrapped around, but without \"modulo_time_base\" changing!\n"); -#endif - ++fSecondsSinceLastTimeCode; - newTotalTicks += vop_time_increment_resolution; - } - fPrevNewTotalTicks = newTotalTicks; - if (vop_coding_type != 2/*B*/) { - int pictureCountDelta = newTotalTicks - fTotalTicksSinceLastTimeCode; - if (pictureCountDelta <= 0) pictureCountDelta = fPrevPictureCountDelta; - // ensures that the picture count is always increasing - usingSource()->fPictureCount += pictureCountDelta; - fPrevPictureCountDelta = pictureCountDelta; - fTotalTicksSinceLastTimeCode = newTotalTicks; - fSecondsSinceLastTimeCode += modulo_time_base; - } - } - } - fJustSawTimeCode = False; // for next time - - // The next thing to parse depends on the code that we just saw, - // but we are assumed to have ended the current picture: - usingSource()->fPictureEndMarker = True; // HACK ##### - switch (next4Bytes) { - case VISUAL_OBJECT_SEQUENCE_END_CODE: { - setParseState(PARSING_VISUAL_OBJECT_SEQUENCE_END_CODE); - break; - } - case VISUAL_OBJECT_SEQUENCE_START_CODE: { - setParseState(PARSING_VISUAL_OBJECT_SEQUENCE_SEEN_CODE); - break; - } - case VISUAL_OBJECT_START_CODE: { - setParseState(PARSING_VISUAL_OBJECT); - break; - } - case GROUP_VOP_START_CODE: { - setParseState(PARSING_GROUP_OF_VIDEO_OBJECT_PLANE); - break; - } - case VOP_START_CODE: { - setParseState(PARSING_VIDEO_OBJECT_PLANE); - break; - } - default: { - if (isVideoObjectStartCode(next4Bytes)) { - setParseState(PARSING_VIDEO_OBJECT_LAYER); - } else { - usingSource()->envir() << "MPEG4VideoStreamParser::parseVideoObjectPlane(): Saw unexpected code " - << (void*)next4Bytes << "\n"; - setParseState(PARSING_VIDEO_OBJECT_PLANE); // the safest way to recover... - } - break; - } - } - - // Compute this frame's presentation time: - usingSource()->computePresentationTime(fTotalTicksSinceLastTimeCode); - - return curFrameSize(); -} - -unsigned MPEG4VideoStreamParser::parseVisualObjectSequenceEndCode() { -#ifdef DEBUG - fprintf(stderr, "parsing VISUAL_OBJECT_SEQUENCE_END_CODE\n"); -#endif - // Note that we've already read the VISUAL_OBJECT_SEQUENCE_END_CODE - save4Bytes(VISUAL_OBJECT_SEQUENCE_END_CODE); - - setParseState(PARSING_VISUAL_OBJECT_SEQUENCE); - - // Treat this as if we had ended a picture: - usingSource()->fPictureEndMarker = True; // HACK ##### - - return curFrameSize(); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamFramer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamFramer.cpp deleted file mode 100644 index f4359a50e2d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamFramer.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an MPEG video elementary stream into -// headers and frames -// Implementation - -#include "MPEGVideoStreamParser.hh" -#include - -////////// TimeCode implementation ////////// - -TimeCode::TimeCode() - : days(0), hours(0), minutes(0), seconds(0), pictures(0) { -} - -TimeCode::~TimeCode() { -} - -int TimeCode::operator==(TimeCode const& arg2) { - return pictures == arg2.pictures && seconds == arg2.seconds - && minutes == arg2.minutes && hours == arg2.hours && days == arg2.days; -} - -////////// MPEGVideoStreamFramer implementation ////////// - -MPEGVideoStreamFramer::MPEGVideoStreamFramer(UsageEnvironment& env, - FramedSource* inputSource) - : FramedFilter(env, inputSource), - fFrameRate(0.0) /* until we learn otherwise */, - fParser(NULL) { - reset(); -} - -MPEGVideoStreamFramer::~MPEGVideoStreamFramer() { - delete fParser; -} - -void MPEGVideoStreamFramer::flushInput() { - reset(); - if (fParser != NULL) fParser->flushInput(); -} - -void MPEGVideoStreamFramer::reset() { - fPictureCount = 0; - fPictureEndMarker = False; - fPicturesAdjustment = 0; - fPictureTimeBase = 0.0; - fTcSecsBase = 0; - fHaveSeenFirstTimeCode = False; - - // Use the current wallclock time as the base 'presentation time': - gettimeofday(&fPresentationTimeBase, NULL); -} - -#ifdef DEBUG -static struct timeval firstPT; -#endif -void MPEGVideoStreamFramer -::computePresentationTime(unsigned numAdditionalPictures) { - // Computes "fPresentationTime" from the most recent GOP's - // time_code, along with the "numAdditionalPictures" parameter: - TimeCode& tc = fCurGOPTimeCode; - - unsigned tcSecs - = (((tc.days*24)+tc.hours)*60+tc.minutes)*60+tc.seconds - fTcSecsBase; - double pictureTime = fFrameRate == 0.0 ? 0.0 - : (tc.pictures + fPicturesAdjustment + numAdditionalPictures)/fFrameRate; - while (pictureTime < fPictureTimeBase) { // "if" should be enough, but just in case - if (tcSecs > 0) tcSecs -= 1; - pictureTime += 1.0; - } - pictureTime -= fPictureTimeBase; - if (pictureTime < 0.0) pictureTime = 0.0; // sanity check - unsigned pictureSeconds = (unsigned)pictureTime; - double pictureFractionOfSecond = pictureTime - (double)pictureSeconds; - - fPresentationTime = fPresentationTimeBase; - fPresentationTime.tv_sec += tcSecs + pictureSeconds; - fPresentationTime.tv_usec += (long)(pictureFractionOfSecond*1000000.0); - if (fPresentationTime.tv_usec >= 1000000) { - fPresentationTime.tv_usec -= 1000000; - ++fPresentationTime.tv_sec; - } -#ifdef DEBUG - if (firstPT.tv_sec == 0 && firstPT.tv_usec == 0) firstPT = fPresentationTime; - struct timeval diffPT; - diffPT.tv_sec = fPresentationTime.tv_sec - firstPT.tv_sec; - diffPT.tv_usec = fPresentationTime.tv_usec - firstPT.tv_usec; - if (fPresentationTime.tv_usec < firstPT.tv_usec) { - --diffPT.tv_sec; - diffPT.tv_usec += 1000000; - } - fprintf(stderr, "MPEGVideoStreamFramer::computePresentationTime(%d) -> %lu.%06ld [%lu.%06ld]\n", numAdditionalPictures, fPresentationTime.tv_sec, fPresentationTime.tv_usec, diffPT.tv_sec, diffPT.tv_usec); -#endif -} - -void MPEGVideoStreamFramer -::setTimeCode(unsigned hours, unsigned minutes, unsigned seconds, - unsigned pictures, unsigned picturesSinceLastGOP) { - TimeCode& tc = fCurGOPTimeCode; // abbrev - unsigned days = tc.days; - if (hours < tc.hours) { - // Assume that the 'day' has wrapped around: - ++days; - } - tc.days = days; - tc.hours = hours; - tc.minutes = minutes; - tc.seconds = seconds; - tc.pictures = pictures; - if (!fHaveSeenFirstTimeCode) { - fPictureTimeBase = fFrameRate == 0.0 ? 0.0 : tc.pictures/fFrameRate; - fTcSecsBase = (((tc.days*24)+tc.hours)*60+tc.minutes)*60+tc.seconds; - fHaveSeenFirstTimeCode = True; - } else if (fCurGOPTimeCode == fPrevGOPTimeCode) { - // The time code has not changed since last time. Adjust for this: - fPicturesAdjustment += picturesSinceLastGOP; - } else { - // Normal case: The time code changed since last time. - fPrevGOPTimeCode = tc; - fPicturesAdjustment = 0; - } -} - -void MPEGVideoStreamFramer::doGetNextFrame() { - fParser->registerReadInterest(fTo, fMaxSize); - continueReadProcessing(); -} - -void MPEGVideoStreamFramer -::continueReadProcessing(void* clientData, - unsigned char* /*ptr*/, unsigned /*size*/, - struct timeval /*presentationTime*/) { - MPEGVideoStreamFramer* framer = (MPEGVideoStreamFramer*)clientData; - framer->continueReadProcessing(); -} - -void MPEGVideoStreamFramer::continueReadProcessing() { - unsigned acquiredFrameSize = fParser->parse(); - if (acquiredFrameSize > 0) { - // We were able to acquire a frame from the input. - // It has already been copied to the reader's space. - fFrameSize = acquiredFrameSize; - fNumTruncatedBytes = fParser->numTruncatedBytes(); - - // "fPresentationTime" should have already been computed. - - // Compute "fDurationInMicroseconds" now: - fDurationInMicroseconds - = (fFrameRate == 0.0 || ((int)fPictureCount) < 0) ? 0 - : (unsigned)((fPictureCount*1000000)/fFrameRate); -#ifdef DEBUG - fprintf(stderr, "fDurationInMicroseconds: %d ((%d*1000000)/%f)\n", fDurationInMicroseconds, fPictureCount, fFrameRate); -#endif - fPictureCount = 0; - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - afterGetting(this); - } else { - // We were unable to parse a complete frame from the input, because: - // - we had to read more data from the source stream, or - // - the source stream has ended. - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamParser.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamParser.cpp deleted file mode 100644 index ee18a9190c3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamParser.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// An abstract parser for MPEG video streams -// Implementation - -#include "MPEGVideoStreamParser.hh" - -MPEGVideoStreamParser -::MPEGVideoStreamParser(MPEGVideoStreamFramer* usingSource, - FramedSource* inputSource) - : StreamParser(inputSource, FramedSource::handleClosure, usingSource, - &MPEGVideoStreamFramer::continueReadProcessing, usingSource), - fUsingSource(usingSource) { -} - -MPEGVideoStreamParser::~MPEGVideoStreamParser() { -} - -void MPEGVideoStreamParser::restoreSavedParserState() { - StreamParser::restoreSavedParserState(); - fTo = fSavedTo; - fNumTruncatedBytes = fSavedNumTruncatedBytes; -} - -void MPEGVideoStreamParser::setParseState() { - fSavedTo = fTo; - fSavedNumTruncatedBytes = fNumTruncatedBytes; - saveParserState(); -} - -void MPEGVideoStreamParser::registerReadInterest(unsigned char* to, - unsigned maxSize) { - fStartOfFrame = fTo = fSavedTo = to; - fLimit = to + maxSize; - fNumTruncatedBytes = fSavedNumTruncatedBytes = 0; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamParser.hh b/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamParser.hh deleted file mode 100644 index 687092ded41..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MPEGVideoStreamParser.hh +++ /dev/null @@ -1,118 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// An abstract parser for MPEG video streams -// C++ header - -#ifndef _MPEG_VIDEO_STREAM_PARSER_HH -#define _MPEG_VIDEO_STREAM_PARSER_HH - -#ifndef _STREAM_PARSER_HH -#include "StreamParser.hh" -#endif -#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH -#include "MPEGVideoStreamFramer.hh" -#endif - -////////// MPEGVideoStreamParser definition ////////// - -class MPEGVideoStreamParser: public StreamParser { -public: - MPEGVideoStreamParser(MPEGVideoStreamFramer* usingSource, - FramedSource* inputSource); - virtual ~MPEGVideoStreamParser(); - -public: - void registerReadInterest(unsigned char* to, unsigned maxSize); - - virtual unsigned parse() = 0; - // returns the size of the frame that was acquired, or 0 if none was - // The number of truncated bytes (if any) is given by: - unsigned numTruncatedBytes() const { return fNumTruncatedBytes; } - -protected: - void setParseState(); - - // Record "byte" in the current output frame: - void saveByte(u_int8_t byte) { - if (fTo >= fLimit) { // there's no space left - ++fNumTruncatedBytes; - return; - } - - *fTo++ = byte; - } - - void save4Bytes(u_int32_t word) { - if (fTo+4 > fLimit) { // there's no space left - fNumTruncatedBytes += 4; - return; - } - - *fTo++ = word>>24; *fTo++ = word>>16; *fTo++ = word>>8; *fTo++ = word; - } - - // Save data until we see a sync word (0x000001xx): - void saveToNextCode(u_int32_t& curWord) { - saveByte(curWord>>24); - curWord = (curWord<<8)|get1Byte(); - while ((curWord&0xFFFFFF00) != 0x00000100) { - if ((unsigned)(curWord&0xFF) > 1) { - // a sync word definitely doesn't begin anywhere in "curWord" - save4Bytes(curWord); - curWord = get4Bytes(); - } else { - // a sync word might begin in "curWord", although not at its start - saveByte(curWord>>24); - unsigned char newByte = get1Byte(); - curWord = (curWord<<8)|newByte; - } - } - } - - // Skip data until we see a sync word (0x000001xx): - void skipToNextCode(u_int32_t& curWord) { - curWord = (curWord<<8)|get1Byte(); - while ((curWord&0xFFFFFF00) != 0x00000100) { - if ((unsigned)(curWord&0xFF) > 1) { - // a sync word definitely doesn't begin anywhere in "curWord" - curWord = get4Bytes(); - } else { - // a sync word might begin in "curWord", although not at its start - unsigned char newByte = get1Byte(); - curWord = (curWord<<8)|newByte; - } - } - } - -protected: - MPEGVideoStreamFramer* fUsingSource; - - // state of the frame that's currently being read: - unsigned char* fStartOfFrame; - unsigned char* fTo; - unsigned char* fLimit; - unsigned fNumTruncatedBytes; - unsigned curFrameSize() { return fTo - fStartOfFrame; } - unsigned char* fSavedTo; - unsigned fSavedNumTruncatedBytes; - -private: // redefined virtual functions - virtual void restoreSavedParserState(); -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/Media.cpp b/mythtv/libs/libmythlivemedia/liveMedia/Media.cpp deleted file mode 100644 index 7e4034899dd..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/Media.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Media -// Implementation - -#include "Media.hh" -#include "HashTable.hh" - -// A data structure for looking up a Medium by its string name -class MediaLookupTable { -public: - static MediaLookupTable* ourMedia(UsageEnvironment& env); - - Medium* lookup(char const* name) const; - // Returns NULL if none already exists - - void addNew(Medium* medium, char* mediumName); - void remove(char const* name); - - void generateNewName(char* mediumName, unsigned maxLen); - -protected: - MediaLookupTable(UsageEnvironment& env); - virtual ~MediaLookupTable(); - -private: - UsageEnvironment& fEnv; - HashTable* fTable; - unsigned fNameGenerator; -}; - - -////////// Medium ////////// - -Medium::Medium(UsageEnvironment& env) - : fEnviron(env), fNextTask(NULL) { - // First generate a name for the new medium: - MediaLookupTable::ourMedia(env)->generateNewName(fMediumName, mediumNameMaxLen); - env.setResultMsg(fMediumName); - - // Then add it to our table: - MediaLookupTable::ourMedia(env)->addNew(this, fMediumName); -} - -Medium::~Medium() { - // Remove any tasks that might be pending for us: - fEnviron.taskScheduler().unscheduleDelayedTask(fNextTask); -} - -Boolean Medium::lookupByName(UsageEnvironment& env, char const* mediumName, - Medium*& resultMedium) { - resultMedium = MediaLookupTable::ourMedia(env)->lookup(mediumName); - if (resultMedium == NULL) { - env.setResultMsg("Medium ", mediumName, " does not exist"); - return False; - } - - return True; -} - -void Medium::close(UsageEnvironment& env, char const* name) { - MediaLookupTable::ourMedia(env)->remove(name); -} - -void Medium::close(Medium* medium) { - if (medium == NULL) return; - - close(medium->envir(), medium->name()); -} - -Boolean Medium::isSource() const { - return False; // default implementation -} - -Boolean Medium::isSink() const { - return False; // default implementation -} - -Boolean Medium::isRTCPInstance() const { - return False; // default implementation -} - -Boolean Medium::isRTSPClient() const { - return False; // default implementation -} - -Boolean Medium::isRTSPServer() const { - return False; // default implementation -} - -Boolean Medium::isMediaSession() const { - return False; // default implementation -} - -Boolean Medium::isServerMediaSession() const { - return False; // default implementation -} - -Boolean Medium::isDarwinInjector() const { - return False; // default implementation -} - - -////////// _Tables implementation ////////// - -_Tables* _Tables::getOurTables(UsageEnvironment& env) { - if (env.liveMediaPriv == NULL) { - env.liveMediaPriv = new _Tables(env); - } - return (_Tables*)(env.liveMediaPriv); -} - -void _Tables::reclaimIfPossible() { - if (mediaTable == NULL && socketTable == NULL) { - fEnv.liveMediaPriv = NULL; - delete this; - } -} - -_Tables::_Tables(UsageEnvironment& env) - : mediaTable(NULL), socketTable(NULL), fEnv(env) { -} - -_Tables::~_Tables() { -} - - -////////// MediaLookupTable implementation ////////// - -MediaLookupTable* MediaLookupTable::ourMedia(UsageEnvironment& env) { - _Tables* ourTables = _Tables::getOurTables(env); - if (ourTables->mediaTable == NULL) { - // Create a new table to record the media that are to be created in - // this environment: - ourTables->mediaTable = new MediaLookupTable(env); - } - return (MediaLookupTable*)(ourTables->mediaTable); -} - -Medium* MediaLookupTable::lookup(char const* name) const { - return (Medium*)(fTable->Lookup(name)); -} - -void MediaLookupTable::addNew(Medium* medium, char* mediumName) { - fTable->Add(mediumName, (void*)medium); -} - -void MediaLookupTable::remove(char const* name) { - Medium* medium = lookup(name); - if (medium != NULL) { - fTable->Remove(name); - if (fTable->IsEmpty()) { - // We can also delete ourselves (to reclaim space): - _Tables* ourTables = _Tables::getOurTables(fEnv); - delete this; - ourTables->mediaTable = NULL; - ourTables->reclaimIfPossible(); - } - - delete medium; - } -} - -void MediaLookupTable::generateNewName(char* mediumName, - unsigned /*maxLen*/) { - // We should really use snprintf() here, but not all systems have it - sprintf(mediumName, "liveMedia%d", fNameGenerator++); -} - -MediaLookupTable::MediaLookupTable(UsageEnvironment& env) - : fEnv(env), fTable(HashTable::create(STRING_HASH_KEYS)), fNameGenerator(0) { -} - -MediaLookupTable::~MediaLookupTable() { - delete fTable; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MediaSession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MediaSession.cpp deleted file mode 100644 index 9c4c7746cf5..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MediaSession.cpp +++ /dev/null @@ -1,1185 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A data structure that represents a session that consists of -// potentially multiple (audio and/or video) sub-sessions -// Implementation - -#include "liveMedia.hh" -#ifdef SUPPORT_REAL_RTSP -#include "../RealRTSP/include/RealRTSP.hh" -#endif -#include "GroupsockHelper.hh" -#include - -////////// MediaSession ////////// - -MediaSession* MediaSession::createNew(UsageEnvironment& env, - char const* sdpDescription) { - MediaSession* newSession = new MediaSession(env); - if (newSession != NULL) { - if (!newSession->initializeWithSDP(sdpDescription)) { - delete newSession; - return NULL; - } - } - - return newSession; -} - -Boolean MediaSession::lookupByName(UsageEnvironment& env, - char const* instanceName, - MediaSession*& resultSession) { - resultSession = NULL; // unless we succeed - - Medium* medium; - if (!Medium::lookupByName(env, instanceName, medium)) return False; - - if (!medium->isMediaSession()) { - env.setResultMsg(instanceName, " is not a 'MediaSession' object"); - return False; - } - - resultSession = (MediaSession*)medium; - return True; -} - -MediaSession::MediaSession(UsageEnvironment& env) - : Medium(env), - fSubsessionsHead(NULL), fSubsessionsTail(NULL), - fConnectionEndpointName(NULL), fMaxPlayEndTime(0.0f), - fScale(1.0f), fMediaSessionType(NULL), fSessionName(NULL), fSessionDescription(NULL) { -#ifdef SUPPORT_REAL_RTSP - RealInitSDPAttributes(this); -#endif - fSourceFilterAddr.s_addr = 0; - - // Get our host name, and use this for the RTCP CNAME: - const unsigned maxCNAMElen = 100; - char CNAME[maxCNAMElen+1]; -#ifndef CRIS - gethostname((char*)CNAME, maxCNAMElen); -#else - // "gethostname()" isn't defined for this platform - sprintf(CNAME, "unknown host %d", (unsigned)(our_random()*0x7FFFFFFF)); -#endif - CNAME[maxCNAMElen] = '\0'; // just in case - fCNAME = strDup(CNAME); -} - -MediaSession::~MediaSession() { - delete fSubsessionsHead; - delete[] fCNAME; - delete[] fConnectionEndpointName; - delete[] fMediaSessionType; - delete[] fSessionName; - delete[] fSessionDescription; -#ifdef SUPPORT_REAL_RTSP - RealReclaimSDPAttributes(this); -#endif -} - -Boolean MediaSession::isMediaSession() const { - return True; -} - -Boolean MediaSession::initializeWithSDP(char const* sdpDescription) { - if (sdpDescription == NULL) return False; - - // Begin by processing all SDP lines until we see the first "m=" - char const* sdpLine = sdpDescription; - char const* nextSDPLine; - while (1) { - if (!parseSDPLine(sdpLine, nextSDPLine)) return False; - //##### We should really check for: - // - "a=control:" attributes (to set the URL for aggregate control) - // - the correct SDP version (v=0) - if (sdpLine[0] == 'm') break; - sdpLine = nextSDPLine; - if (sdpLine == NULL) break; // there are no m= lines at all - - // Check for various special SDP lines that we understand: - if (parseSDPLine_s(sdpLine)) continue; - if (parseSDPLine_i(sdpLine)) continue; - if (parseSDPLine_c(sdpLine)) continue; - if (parseSDPAttribute_range(sdpLine)) continue; - if (parseSDPAttribute_type(sdpLine)) continue; - if (parseSDPAttribute_source_filter(sdpLine)) continue; -#ifdef SUPPORT_REAL_RTSP - if (RealParseSDPAttributes(this, sdpLine)) continue; -#endif - } - - while (sdpLine != NULL) { - // We have a "m=" line, representing a new sub-session: - MediaSubsession* subsession = new MediaSubsession(*this); - if (subsession == NULL) { - envir().setResultMsg("Unable to create new MediaSubsession"); - return False; - } - - // Parse the line as "m= RTP/AVP " - // or "m= / RTP/AVP " - // (Should we be checking for >1 payload format number here?)##### - char* mediumName = strDupSize(sdpLine); // ensures we have enough space - char* protocolName = NULL; - unsigned payloadFormat; - if ((sscanf(sdpLine, "m=%s %hu RTP/AVP %u", - mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 || - sscanf(sdpLine, "m=%s %hu/%*u RTP/AVP %u", - mediumName, &subsession->fClientPortNum, &payloadFormat) == 3) - && payloadFormat <= 127) { - protocolName = "RTP"; - } else if ((sscanf(sdpLine, "m=%s %hu UDP %u", - mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 || - sscanf(sdpLine, "m=%s %hu udp %u", - mediumName, &subsession->fClientPortNum, &payloadFormat) == 3 || - sscanf(sdpLine, "m=%s %hu RAW/RAW/UDP %u", - mediumName, &subsession->fClientPortNum, &payloadFormat) == 3) - && payloadFormat <= 127) { - // This is a RAW UDP source - protocolName = "UDP"; - } else { - // This "m=" line is bad; output an error message saying so: - char* sdpLineStr; - if (nextSDPLine == NULL) { - sdpLineStr = (char*)sdpLine; - } else { - sdpLineStr = strDup(sdpLine); - sdpLineStr[nextSDPLine-sdpLine] = '\0'; - } - envir() << "Bad SDP \"m=\" line: " << sdpLineStr << "\n"; - if (sdpLineStr != (char*)sdpLine) delete[] sdpLineStr; - - delete[] mediumName; - delete subsession; - - // Skip the following SDP lines, up until the next "m=": - while (1) { - sdpLine = nextSDPLine; - if (sdpLine == NULL) break; // we've reached the end - if (!parseSDPLine(sdpLine, nextSDPLine)) return False; - - if (sdpLine[0] == 'm') break; // we've reached the next subsession - } - continue; - } - - // Insert this subsession at the end of the list: - if (fSubsessionsTail == NULL) { - fSubsessionsHead = fSubsessionsTail = subsession; - } else { - fSubsessionsTail->setNext(subsession); - fSubsessionsTail = subsession; - } - - subsession->serverPortNum = subsession->fClientPortNum; // by default - - char const* mStart = sdpLine; - subsession->fSavedSDPLines = strDup(mStart); - - subsession->fMediumName = strDup(mediumName); - delete[] mediumName; - subsession->fProtocolName = strDup(protocolName); - subsession->fRTPPayloadFormat = payloadFormat; - - // Process the following SDP lines, up until the next "m=": - while (1) { - sdpLine = nextSDPLine; - if (sdpLine == NULL) break; // we've reached the end - if (!parseSDPLine(sdpLine, nextSDPLine)) return False; - - if (sdpLine[0] == 'm') break; // we've reached the next subsession - - // Check for various special SDP lines that we understand: - if (subsession->parseSDPLine_c(sdpLine)) continue; - if (subsession->parseSDPAttribute_rtpmap(sdpLine)) continue; - if (subsession->parseSDPAttribute_control(sdpLine)) continue; - if (subsession->parseSDPAttribute_range(sdpLine)) continue; - if (subsession->parseSDPAttribute_fmtp(sdpLine)) continue; - if (subsession->parseSDPAttribute_source_filter(sdpLine)) continue; - if (subsession->parseSDPAttribute_x_mct_slap(sdpLine)) continue; - if (subsession->parseSDPAttribute_x_dimensions(sdpLine)) continue; - if (subsession->parseSDPAttribute_x_framerate(sdpLine)) continue; -#ifdef SUPPORT_REAL_RTSP - if (RealParseSDPAttributes(subsession, sdpLine)) continue; -#endif - - // (Later, check for malformed lines, and other valid SDP lines#####) - } - if (sdpLine != NULL) subsession->fSavedSDPLines[sdpLine-mStart] = '\0'; - - // If we don't yet know the codec name, try looking it up from the - // list of static payload types: - if (subsession->fCodecName == NULL) { - subsession->fCodecName - = lookupPayloadFormat(subsession->fRTPPayloadFormat, - subsession->fRTPTimestampFrequency, - subsession->fNumChannels); - if (subsession->fCodecName == NULL) { - char typeStr[20]; - sprintf(typeStr, "%d", subsession->fRTPPayloadFormat); - envir().setResultMsg("Unknown codec name for RTP payload type ", - typeStr); - return False; - } - } - - // If we don't yet know this subsession's RTP timestamp frequency - // (because it uses a dynamic payload type and the corresponding - // SDP "rtpmap" attribute erroneously didn't specify it), - // then guess it now: - if (subsession->fRTPTimestampFrequency == 0) { - subsession->fRTPTimestampFrequency - = guessRTPTimestampFrequency(subsession->fMediumName, - subsession->fCodecName); - } - } - - return True; -} - -Boolean MediaSession::parseSDPLine(char const* inputLine, - char const*& nextLine){ - // Begin by finding the start of the next line (if any): - nextLine = NULL; - for (char const* ptr = inputLine; *ptr != '\0'; ++ptr) { - if (*ptr == '\r' || *ptr == '\n') { - // We found the end of the line - ++ptr; - while (*ptr == '\r' || *ptr == '\n') ++ptr; - nextLine = ptr; - if (nextLine[0] == '\0') nextLine = NULL; // special case for end - break; - } - } - - // Then, check that this line is a SDP line of the form = - // (However, we also accept blank lines in the input.) - if (inputLine[0] == '\r' || inputLine[0] == '\n') return True; - if (strlen(inputLine) < 2 || inputLine[1] != '=' - || inputLine[0] < 'a' || inputLine[0] > 'z') { - envir().setResultMsg("Invalid SDP line: ", inputLine); - return False; - } - - return True; -} - -static char* parseCLine(char const* sdpLine) { - char* resultStr = NULL; - char* buffer = strDupSize(sdpLine); // ensures we have enough space - if (sscanf(sdpLine, "c=IN IP4 %[^/ ]", buffer) == 1) { - // Later, handle the optional / and / ##### - resultStr = strDup(buffer); - } - delete[] buffer; - - return resultStr; -} - -Boolean MediaSession::parseSDPLine_s(char const* sdpLine) { - // Check for "s=" line - char* buffer = strDupSize(sdpLine); - Boolean parseSuccess = False; - - if (sscanf(sdpLine, "s=%[^\r\n]", buffer) == 1) { - delete[] fSessionName; fSessionName = strDup(buffer); - parseSuccess = True; - } - delete[] buffer; - - return parseSuccess; -} - -Boolean MediaSession::parseSDPLine_i(char const* sdpLine) { - // Check for "i=" line - char* buffer = strDupSize(sdpLine); - Boolean parseSuccess = False; - - if (sscanf(sdpLine, "i=%[^\r\n]", buffer) == 1) { - delete[] fSessionDescription; fSessionDescription = strDup(buffer); - parseSuccess = True; - } - delete[] buffer; - - return parseSuccess; -} - -Boolean MediaSession::parseSDPLine_c(char const* sdpLine) { - // Check for "c=IN IP4 " - // or "c=IN IP4 /" - // (Later, do something with also #####) - char* connectionEndpointName = parseCLine(sdpLine); - if (connectionEndpointName != NULL) { - delete[] fConnectionEndpointName; - fConnectionEndpointName = connectionEndpointName; - return True; - } - - return False; -} - -Boolean MediaSession::parseSDPAttribute_type(char const* sdpLine) { - // Check for a "a=type:broadcast|meeting|moderated|test|H.332|recvonly" line: - Boolean parseSuccess = False; - - char* buffer = strDupSize(sdpLine); - if (sscanf(sdpLine, "a=type: %[^ ]", buffer) == 1) { - delete[] fMediaSessionType; - fMediaSessionType = strDup(buffer); - parseSuccess = True; - } - delete[] buffer; - - return parseSuccess; -} - -static Boolean parseRangeAttribute(char const* sdpLine, float& endTime) { - return sscanf(sdpLine, "a=range: npt = %*g - %g", &endTime) == 1; -} - -Boolean MediaSession::parseSDPAttribute_range(char const* sdpLine) { - // Check for a "a=range:npt=-" line: - // (Later handle other kinds of "a=range" attributes also???#####) - Boolean parseSuccess = False; - - float playEndTime; - if (parseRangeAttribute(sdpLine, playEndTime)) { - parseSuccess = True; - if (playEndTime > fMaxPlayEndTime) { - fMaxPlayEndTime = playEndTime; - } - } - - return parseSuccess; -} - -static Boolean parseSourceFilterAttribute(char const* sdpLine, - struct in_addr& sourceAddr) { - // Check for a "a=source-filter:incl IN IP4 " line. - // Note: At present, we don't check that really matches - // one of our multicast addresses. We also don't support more than - // one ##### - Boolean result = False; // until we succeed - char* sourceName = strDupSize(sdpLine); // ensures we have enough space - do { - if (sscanf(sdpLine, "a=source-filter: incl IN IP4 %*s %s", - sourceName) != 1) break; - - // Now, convert this name to an address, if we can: - NetAddressList addresses(sourceName); - if (addresses.numAddresses() == 0) break; - - netAddressBits sourceAddrBits - = *(netAddressBits*)(addresses.firstAddress()->data()); - if (sourceAddrBits == 0) break; - - sourceAddr.s_addr = sourceAddrBits; - result = True; - } while (0); - - delete[] sourceName; - return result; -} - -Boolean MediaSession -::parseSDPAttribute_source_filter(char const* sdpLine) { - return parseSourceFilterAttribute(sdpLine, fSourceFilterAddr); -} - -char* MediaSession::lookupPayloadFormat(unsigned char rtpPayloadType, - unsigned& freq, unsigned& nCh) { - // Look up the codec name and timestamp frequency for known (static) - // RTP payload formats. - char* temp = NULL; - switch (rtpPayloadType) { - case 0: {temp = "PCMU"; freq = 8000; nCh = 1; break;} - case 2: {temp = "G726-32"; freq = 8000; nCh = 1; break;} - case 3: {temp = "GSM"; freq = 8000; nCh = 1; break;} - case 4: {temp = "G723"; freq = 8000; nCh = 1; break;} - case 5: {temp = "DVI4"; freq = 8000; nCh = 1; break;} - case 6: {temp = "DVI4"; freq = 16000; nCh = 1; break;} - case 7: {temp = "LPC"; freq = 8000; nCh = 1; break;} - case 8: {temp = "PCMA"; freq = 8000; nCh = 1; break;} - case 9: {temp = "G722"; freq = 8000; nCh = 1; break;} - case 10: {temp = "L16"; freq = 44100; nCh = 2; break;} - case 11: {temp = "L16"; freq = 44100; nCh = 1; break;} - case 12: {temp = "QCELP"; freq = 8000; nCh = 1; break;} - case 14: {temp = "MPA"; freq = 90000; nCh = 1; break;} - // 'number of channels' is actually encoded in the media stream - case 15: {temp = "G728"; freq = 8000; nCh = 1; break;} - case 16: {temp = "DVI4"; freq = 11025; nCh = 1; break;} - case 17: {temp = "DVI4"; freq = 22050; nCh = 1; break;} - case 18: {temp = "G729"; freq = 8000; nCh = 1; break;} - case 25: {temp = "CELB"; freq = 90000; nCh = 1; break;} - case 26: {temp = "JPEG"; freq = 90000; nCh = 1; break;} - case 28: {temp = "NV"; freq = 90000; nCh = 1; break;} - case 31: {temp = "H261"; freq = 90000; nCh = 1; break;} - case 32: {temp = "MPV"; freq = 90000; nCh = 1; break;} - case 33: {temp = "MP2T"; freq = 90000; nCh = 1; break;} - case 34: {temp = "H263"; freq = 90000; nCh = 1; break;} - }; - - return strDup(temp); -} - -unsigned MediaSession::guessRTPTimestampFrequency(char const* mediumName, - char const* codecName) { - // By default, we assume that audio sessions use a frequency of 8000, - // and that video sessions use a frequency of 90000. - // Begin by checking for known exceptions to this rule - // (where the frequency is known unambiguously (e.g., not like "DVI4")) - if (strcmp(codecName, "L16") == 0) return 44100; - if (strcmp(codecName, "MPA") == 0 - || strcmp(codecName, "MPA-ROBUST") == 0 - || strcmp(codecName, "X-MP3-DRAFT-00")) return 90000; - - // Now, guess default values: - if (strcmp(mediumName, "video") == 0) return 90000; - return 8000; // for "audio", and any other medium -} - -static unsigned computeSeqNumStagger(unsigned staggerSeconds) { - // To compute the sequence number stagger, assume - // - one MP3 frame per packet - // - 1152 samples per MP3 frame (defined by MP3 standard) - // - a sampling frequency of 44100 Hz - // (Later, allow this to be parameterized)##### - unsigned const samplesPerFrame = 1152; - unsigned samplesPerSecond = 44100; - double secondsPerFrame = (double)samplesPerFrame/samplesPerSecond; - return (unsigned)(staggerSeconds/secondsPerFrame); -} - -Boolean MediaSession -::initiateByMediaType(char const* mimeType, - MediaSubsession*& resultSubsession, - PrioritizedRTPStreamSelector*& resultMultiSource, - int& resultMultiSourceSessionId, - int useSpecialRTPoffset) { - // Look through this session's subsessions for media that match "mimeType" - resultSubsession = NULL; - resultMultiSource = NULL; - resultMultiSourceSessionId = 0; - unsigned maxStaggerSeconds = 0; - MediaSubsessionIterator iter(*this); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - if (resultMultiSourceSessionId != 0 - && subsession->mctSLAPSessionId() != resultMultiSourceSessionId) { - // We're using a multi-source SLAP session, but this subsession - // isn't part of it - continue; - } - - Boolean wasAlreadyInitiated = subsession->readSource() != NULL; - if (!wasAlreadyInitiated) { - // Try to create a source for this subsession: - if (!subsession->initiate(useSpecialRTPoffset)) return False; - } - - // Make sure the source's MIME type is one that we handle: - if (strcmp(subsession->readSource()->MIMEtype(), mimeType) != 0) { - if (!wasAlreadyInitiated) subsession->deInitiate(); - continue; - } - - if (subsession->mctSLAPSessionId() == 0) { - // Normal case: a single session - resultSubsession = subsession; - break; // use this - } else { - // Special case: a multi-source SLAP session - resultMultiSourceSessionId = subsession->mctSLAPSessionId(); - unsigned subsessionStaggerSeconds = subsession->mctSLAPStagger(); - if (subsessionStaggerSeconds > maxStaggerSeconds) { - maxStaggerSeconds = subsessionStaggerSeconds; - } - } - } - - if (resultSubsession == NULL && resultMultiSourceSessionId == 0) { - envir().setResultMsg("Session has no usable media subsession"); - return False; - } - - if (resultMultiSourceSessionId != 0) { - // We have a multi-source MCT SLAP session; create a selector for it: - unsigned seqNumStagger = computeSeqNumStagger(maxStaggerSeconds); - resultMultiSource - = PrioritizedRTPStreamSelector::createNew(envir(), seqNumStagger); - if (resultMultiSource == NULL) return False; - // Note: each subsession has its own RTCP instance; we don't return them - - // Then run through the subsessions again, adding each of the sources: - iter.reset(); - while ((subsession = iter.next()) != NULL) { - if (subsession->mctSLAPSessionId() == resultMultiSourceSessionId) { - resultMultiSource->addInputRTPStream(subsession->rtpSource(), - subsession->rtcpInstance()); - } - } - } - - return True; -} - - -////////// MediaSubsessionIterator ////////// - -MediaSubsessionIterator::MediaSubsessionIterator(MediaSession& session) - : fOurSession(session) { - reset(); -} - -MediaSubsessionIterator::~MediaSubsessionIterator() { -} - -MediaSubsession* MediaSubsessionIterator::next() { - MediaSubsession* result = fNextPtr; - - if (fNextPtr != NULL) fNextPtr = fNextPtr->fNext; - - return result; -} - -void MediaSubsessionIterator::reset() { - fNextPtr = fOurSession.fSubsessionsHead; -} - -////////// MediaSubsession ////////// - -MediaSubsession::MediaSubsession(MediaSession& parent) - : sessionId(NULL), serverPortNum(0), sink(NULL), miscPtr(NULL), - fParent(parent), fNext(NULL), - fConnectionEndpointName(NULL), - fClientPortNum(0), fRTPPayloadFormat(0xFF), - fSavedSDPLines(NULL), fMediumName(NULL), fCodecName(NULL), fProtocolName(NULL), - fRTPTimestampFrequency(0), fControlPath(NULL), - fSourceFilterAddr(parent.sourceFilterAddr()), - fAuxiliarydatasizelength(0), fConstantduration(0), fConstantsize(0), - fCRC(0), fCtsdeltalength(0), fDe_interleavebuffersize(0), fDtsdeltalength(0), - fIndexdeltalength(0), fIndexlength(0), fInterleaving(0), fMaxdisplacement(0), - fObjecttype(0), fOctetalign(0), fProfile_level_id(0), fRobustsorting(0), - fSizelength(0), fStreamstateindication(0), fStreamtype(0), - fCpresent(False), fRandomaccessindication(False), - fConfig(NULL), fMode(NULL), fSpropParameterSets(NULL), - fPlayEndTime(0.0), - fMCT_SLAP_SessionId(0), fMCT_SLAP_Stagger(0), - fVideoWidth(0), fVideoHeight(0), fVideoFPS(0), fNumChannels(1), fScale(1.0f), - fRTPSocket(NULL), fRTCPSocket(NULL), - fRTPSource(NULL), fRTCPInstance(NULL), fReadSource(NULL) { -#ifdef SUPPORT_REAL_RTSP - RealInitSDPAttributes(this); -#endif -} - -MediaSubsession::~MediaSubsession() { - deInitiate(); - - delete[] fConnectionEndpointName; delete[] fSavedSDPLines; - delete[] fMediumName; delete[] fCodecName; delete[] fProtocolName; - delete[] fControlPath; delete[] fConfig; delete[] fMode; delete[] fSpropParameterSets; - - delete fNext; -#ifdef SUPPORT_REAL_RTSP - RealReclaimSDPAttributes(this); -#endif -} - -float MediaSubsession::playEndTime() const { - if (fPlayEndTime > 0) return fPlayEndTime; - - return fParent.playEndTime(); -} - -Boolean MediaSubsession::initiate(int useSpecialRTPoffset) { - if (fReadSource != NULL) return True; // has already been initiated - - do { - if (fCodecName == NULL) { - env().setResultMsg("Codec is unspecified"); - break; - } - - // Create RTP and RTCP 'Groupsocks' on which to receive incoming data. - // (Groupsocks will work even for unicast addresses) - Groupsock* oldGroupsock = NULL; - Boolean success = False; - struct in_addr tempAddr; - tempAddr.s_addr = connectionEndpointAddress(); - // This could get changed later, as a result of a RTSP "SETUP" - while (1) { - unsigned short rtpPortNum = fClientPortNum&~1; - if (isSSM()) { - fRTPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, - rtpPortNum); - } else { - fRTPSocket = new Groupsock(env(), tempAddr, rtpPortNum, 255); - } - if (fRTPSocket == NULL) { - env().setResultMsg("Failed to create RTP socket"); - break; - } - - // Get the client port number, to make sure that it's even (for RTP): - Port clientPort(0); - if (!getSourcePort(env(), fRTPSocket->socketNum(), clientPort)) { - break; - } - fClientPortNum = ntohs(clientPort.num()); - - // If the port number's not even, try again: - if ((fClientPortNum&1) == 0) { - success = True; - break; - } - // Try again: - delete oldGroupsock; - oldGroupsock = fRTPSocket; - fClientPortNum = 0; - } - delete oldGroupsock; - if (!success) break; - - // Set our RTCP port to be the RTP port +1 - unsigned short const rtcpPortNum = fClientPortNum|1; - if (isSSM()) { - fRTCPSocket = new Groupsock(env(), tempAddr, fSourceFilterAddr, - rtcpPortNum); - // Also, send RTCP packets back to the source via unicast: - if (fRTCPSocket != NULL) { - fRTCPSocket->changeDestinationParameters(fSourceFilterAddr,0,~0); - } - } else { - fRTCPSocket = new Groupsock(env(), tempAddr, rtcpPortNum, 255); - } - if (fRTCPSocket == NULL) { - char tmpBuf[100]; - sprintf(tmpBuf, "Failed to create RTCP socket (port %d)", - rtcpPortNum); - env().setResultMsg(tmpBuf); - break; - } - - // Check "fProtocolName" - if (strcmp(fProtocolName, "UDP") == 0) { - // A UDP-packetized stream (*not* a RTP stream) - fReadSource = BasicUDPSource::createNew(env(), fRTPSocket); - fRTPSource = NULL; // Note! - - if (strcmp(fCodecName, "MP2T") == 0) { // MPEG-2 Transport Stream - fReadSource = MPEG2TransportStreamFramer::createNew(env(), fReadSource); - // this sets "durationInMicroseconds" correctly, based on the PCR values - } - } else { - // Check "fCodecName" against the set of codecs that we support, - // and create our RTP source accordingly - // (Later make this code more efficient, as this set grows #####) - // (Also, add more fmts that can be implemented by SimpleRTPSource#####) - Boolean createSimpleRTPSource = False; - Boolean doNormalMBitRule = False; // used if "createSimpleRTPSource" - if (strcmp(fCodecName, "QCELP") == 0) { // QCELP audio - fReadSource = - QCELPAudioRTPSource::createNew(env(), fRTPSocket, fRTPSource, - fRTPPayloadFormat, - fRTPTimestampFrequency); - // Note that fReadSource will differ from fRTPSource in this case - } else if (strcmp(fCodecName, "AMR") == 0) { // AMR audio (narrowband) - fReadSource = - AMRAudioRTPSource::createNew(env(), fRTPSocket, fRTPSource, - fRTPPayloadFormat, 0 /*isWideband*/, - fNumChannels, fOctetalign, fInterleaving, - fRobustsorting, fCRC); - // Note that fReadSource will differ from fRTPSource in this case - } else if (strcmp(fCodecName, "AMR-WB") == 0) { // AMR audio (wideband) - fReadSource = - AMRAudioRTPSource::createNew(env(), fRTPSocket, fRTPSource, - fRTPPayloadFormat, 1 /*isWideband*/, - fNumChannels, fOctetalign, fInterleaving, - fRobustsorting, fCRC); - // Note that fReadSource will differ from fRTPSource in this case - } else if (strcmp(fCodecName, "MPA") == 0) { // MPEG-1 or 2 audio - fReadSource = fRTPSource - = MPEG1or2AudioRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "MPA-ROBUST") == 0) { // robust MP3 audio - fRTPSource - = MP3ADURTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, - fRTPTimestampFrequency); - if (fRTPSource == NULL) break; - - // Add a filter that deinterleaves the ADUs after depacketizing them: - MP3ADUdeinterleaver* deinterleaver - = MP3ADUdeinterleaver::createNew(env(), fRTPSource); - if (deinterleaver == NULL) break; - - // Add another filter that converts these ADUs to MP3 frames: - fReadSource = MP3FromADUSource::createNew(env(), deinterleaver); - } else if (strcmp(fCodecName, "X-MP3-DRAFT-00") == 0) { - // a non-standard variant of "MPA-ROBUST" used by RealNetworks - // (one 'ADU'ized MP3 frame per packet; no headers) - fRTPSource - = SimpleRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, - fRTPTimestampFrequency, - "audio/MPA-ROBUST" /*hack*/); - if (fRTPSource == NULL) break; - - // Add a filter that converts these ADUs to MP3 frames: - fReadSource = MP3FromADUSource::createNew(env(), fRTPSource, - False /*no ADU header*/); - } else if (strcmp(fCodecName, "MP4A-LATM") == 0) { // MPEG-4 LATM audio - fReadSource = fRTPSource - = MPEG4LATMAudioRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "AC3") == 0) { // AC3 audio - fReadSource = fRTPSource - = AC3AudioRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "MP4V-ES") == 0) { // MPEG-4 Elem Str vid - fReadSource = fRTPSource - = MPEG4ESVideoRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "MPEG4-GENERIC") == 0) { - fReadSource = fRTPSource - = MPEG4GenericRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency, - fMediumName, fMode, - fSizelength, fIndexlength, - fIndexdeltalength); - } else if (strcmp(fCodecName, "MPV") == 0) { // MPEG-1 or 2 video - fReadSource = fRTPSource - = MPEG1or2VideoRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "MP2T") == 0) { // MPEG-2 Transport Stream - fRTPSource = SimpleRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, - fRTPTimestampFrequency, "video/MP2T", - 0, False); - fReadSource = MPEG2TransportStreamFramer::createNew(env(), fRTPSource); - // this sets "durationInMicroseconds" correctly, based on the PCR values - } else if (strcmp(fCodecName, "H261") == 0) { // H.261 - fReadSource = fRTPSource - = H261VideoRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "H263-1998") == 0 || - strcmp(fCodecName, "H263-2000") == 0) { // H.263+ - fReadSource = fRTPSource - = H263plusVideoRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "H264") == 0) { - fReadSource = fRTPSource - = H264VideoRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "JPEG") == 0) { // motion JPEG - fReadSource = fRTPSource - = JPEGVideoRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency); - } else if (strcmp(fCodecName, "X-QT") == 0 - || strcmp(fCodecName, "X-QUICKTIME") == 0) { - // Generic QuickTime streams, as defined in - // - char* mimeType - = new char[strlen(mediumName()) + strlen(codecName()) + 2] ; - sprintf(mimeType, "%s/%s", mediumName(), codecName()); - fReadSource = fRTPSource - = QuickTimeGenericRTPSource::createNew(env(), fRTPSocket, - fRTPPayloadFormat, - fRTPTimestampFrequency, - mimeType); - delete[] mimeType; -#ifdef SUPPORT_REAL_RTSP - } else if (strcmp(fCodecName, "X-PN-REALAUDIO") == 0 || - strcmp(fCodecName, "X-PN-MULTIRATE-REALAUDIO-LIVE") == 0 || - strcmp(fCodecName, "X-PN-REALVIDEO") == 0 || - strcmp(fCodecName, "X-PN-MULTIRATE-REALVIDEO-LIVE") == 0) { - // A RealNetworks 'RDT' stream (*not* a RTP stream) - fReadSource = RealRDTSource::createNew(env()); - fRTPSource = NULL; // Note! - parentSession().isRealNetworksRDT = True; -#endif - } else if ( strcmp(fCodecName, "PCMU") == 0 // PCM u-law audio - || strcmp(fCodecName, "GSM") == 0 // GSM audio - || strcmp(fCodecName, "PCMA") == 0 // PCM a-law audio - || strcmp(fCodecName, "L16") == 0 // 16-bit linear audio - || strcmp(fCodecName, "MP1S") == 0 // MPEG-1 System Stream - || strcmp(fCodecName, "MP2P") == 0 // MPEG-2 Program Stream - || strcmp(fCodecName, "L8") == 0 // 8-bit linear audio - || strcmp(fCodecName, "G726-16") == 0 // G.726, 16 kbps - || strcmp(fCodecName, "G726-24") == 0 // G.726, 24 kbps - || strcmp(fCodecName, "G726-32") == 0 // G.726, 32 kbps - || strcmp(fCodecName, "G726-40") == 0 // G.726, 40 kbps - || strcmp(fCodecName, "SPEEX") == 0 // SPEEX audio - ) { - createSimpleRTPSource = True; - useSpecialRTPoffset = 0; - } else if (useSpecialRTPoffset >= 0) { - // We don't know this RTP payload format, but try to receive - // it using a 'SimpleRTPSource' with the specified header offset: - createSimpleRTPSource = True; - } else { - env().setResultMsg("RTP payload format unknown or not supported"); - break; - } - - if (createSimpleRTPSource) { - char* mimeType - = new char[strlen(mediumName()) + strlen(codecName()) + 2] ; - sprintf(mimeType, "%s/%s", mediumName(), codecName()); - fReadSource = fRTPSource - = SimpleRTPSource::createNew(env(), fRTPSocket, fRTPPayloadFormat, - fRTPTimestampFrequency, mimeType, - (unsigned)useSpecialRTPoffset, - doNormalMBitRule); - delete[] mimeType; - } - } - - if (fReadSource == NULL) { - env().setResultMsg("Failed to create read source"); - break; - } - - // Finally, create our RTCP instance. (It starts running automatically) - if (fRTPSource != NULL) { - unsigned totSessionBandwidth = 500; // HACK - later get from SDP##### - fRTCPInstance = RTCPInstance::createNew(env(), fRTCPSocket, - totSessionBandwidth, - (unsigned char const*) - fParent.CNAME(), - NULL /* we're a client */, - fRTPSource); - if (fRTCPInstance == NULL) { - env().setResultMsg("Failed to create RTCP instance"); - break; - } - } - - return True; - } while (0); - - delete fRTPSocket; fRTPSocket = NULL; - delete fRTCPSocket; fRTCPSocket = NULL; - Medium::close(fRTCPInstance); fRTCPInstance = NULL; - Medium::close(fReadSource); fReadSource = fRTPSource = NULL; - fClientPortNum = 0; - return False; -} - -void MediaSubsession::deInitiate() { - Medium::close(fRTCPInstance); - fRTCPInstance = NULL; - - Medium::close(fReadSource); // this is assumed to also close fRTPSource - fReadSource = NULL; fRTPSource = NULL; - - delete fRTCPSocket; delete fRTPSocket; - fRTCPSocket = fRTPSocket = NULL; -} - -Boolean MediaSubsession::setClientPortNum(unsigned short portNum) { - if (fReadSource != NULL) { - env().setResultMsg("A read source has already been created"); - return False; - } - - fClientPortNum = portNum; - return True; -} - -unsigned MediaSubsession::connectionEndpointAddress() const { - do { - // Get the endpoint name from with us, or our parent session: - char const* endpointString = connectionEndpointName(); - if (endpointString == NULL) { - endpointString = parentSession().connectionEndpointName(); - } - if (endpointString == NULL) break; - - // Now, convert this name to an address, if we can: - NetAddressList addresses(endpointString); - if (addresses.numAddresses() == 0) break; - - return *(unsigned*)(addresses.firstAddress()->data()); - } while (0); - - // No address known: - return 0; -} - -void MediaSubsession::setDestinations(unsigned defaultDestAddress) { - // Get the destination address from the connection endpoint name - // (This will be 0 if it's not known, in which case we use the default) - unsigned destAddress = connectionEndpointAddress(); - if (destAddress == 0) destAddress = defaultDestAddress; - struct in_addr destAddr; destAddr.s_addr = destAddress; - - // The destination TTL remains unchanged: - int destTTL = ~0; // means: don't change - - if (fRTPSocket != NULL) { - Port destPort(serverPortNum); - fRTPSocket->changeDestinationParameters(destAddr, destPort, destTTL); - } - if (fRTCPSocket != NULL && !isSSM()) { - // Note: For SSM sessions, the dest address for RTCP was already set. - Port destPort(serverPortNum+1); - fRTCPSocket-> - changeDestinationParameters(destAddr, destPort, destTTL); - } -} - -Boolean MediaSubsession::parseSDPLine_c(char const* sdpLine) { - // Check for "c=IN IP4 " - // or "c=IN IP4 /" - // (Later, do something with also #####) - char* connectionEndpointName = parseCLine(sdpLine); - if (connectionEndpointName != NULL) { - delete[] fConnectionEndpointName; - fConnectionEndpointName = connectionEndpointName; - return True; - } - - return False; -} - -Boolean MediaSubsession::parseSDPAttribute_rtpmap(char const* sdpLine) { - // Check for a "a=rtpmap: /" line: - // (Also check without the "/"; RealNetworks omits this) - // Also check for a trailing "/". - Boolean parseSuccess = False; - - unsigned rtpmapPayloadFormat; - char* codecName = strDupSize(sdpLine); // ensures we have enough space - unsigned rtpTimestampFrequency = 0; - unsigned numChannels = 1; - if (sscanf(sdpLine, "a=rtpmap: %u %[^/]/%u/%u", - &rtpmapPayloadFormat, codecName, &rtpTimestampFrequency, - &numChannels) == 4 - || sscanf(sdpLine, "a=rtpmap: %u %[^/]/%u", - &rtpmapPayloadFormat, codecName, &rtpTimestampFrequency) == 3 - || sscanf(sdpLine, "a=rtpmap: %u %s", - &rtpmapPayloadFormat, codecName) == 2) { - parseSuccess = True; - if (rtpmapPayloadFormat == fRTPPayloadFormat) { - // This "rtpmap" matches our payload format, so set our - // codec name and timestamp frequency: - // (First, make sure the codec name is upper case) - for (char* p = codecName; *p != '\0'; ++p) { - *p = toupper(*p); - } - delete[] fCodecName; fCodecName = strDup(codecName); - fRTPTimestampFrequency = rtpTimestampFrequency; - fNumChannels = numChannels; - } - } - delete[] codecName; - - return parseSuccess; -} - -Boolean MediaSubsession::parseSDPAttribute_control(char const* sdpLine) { - // Check for a "a=control:" line: - Boolean parseSuccess = False; - - char* controlPath = strDupSize(sdpLine); // ensures we have enough space - if (sscanf(sdpLine, "a=control: %s", controlPath) == 1) { - parseSuccess = True; - delete[] fControlPath; fControlPath = strDup(controlPath); - } - delete[] controlPath; - - return parseSuccess; -} - -Boolean MediaSubsession::parseSDPAttribute_range(char const* sdpLine) { - // Check for a "a=range:npt=-" line: - // (Later handle other kinds of "a=range" attributes also???#####) - Boolean parseSuccess = False; - - float playEndTime; - if (parseRangeAttribute(sdpLine, playEndTime)) { - parseSuccess = True; - if (playEndTime > fPlayEndTime) { - fPlayEndTime = playEndTime; - if (playEndTime > fParent.playEndTime()) { - fParent.playEndTime() = playEndTime; - } - } - } - - return parseSuccess; -} - -Boolean MediaSubsession::parseSDPAttribute_fmtp(char const* sdpLine) { - // Check for a "a=fmtp:" line: - // TEMP: We check only for a handful of expected parameter names ##### - // Later: (i) check that payload format number matches; ##### - // (ii) look for other parameters also (generalize?) ##### - do { - if (strncmp(sdpLine, "a=fmtp:", 7) != 0) break; sdpLine += 7; - while (isdigit(*sdpLine)) ++sdpLine; - - // The remaining "sdpLine" should be a sequence of - // =; - // parameter assignments. Look at each of these. - // First, convert the line to lower-case, to ease comparison: - char* const lineCopy = strDup(sdpLine); char* line = lineCopy; - for (char* c = line; *c != '\0'; ++c) *c = tolower(*c); - while (*line != '\0' && *line != '\r' && *line != '\n') { - unsigned u; - char* valueStr = strDupSize(line); - if (sscanf(line, " auxiliarydatasizelength = %u", &u) == 1) { - fAuxiliarydatasizelength = u; - } else if (sscanf(line, " constantduration = %u", &u) == 1) { - fConstantduration = u; - } else if (sscanf(line, " constantsize; = %u", &u) == 1) { - fConstantsize = u; - } else if (sscanf(line, " crc = %u", &u) == 1) { - fCRC = u; - } else if (sscanf(line, " ctsdeltalength = %u", &u) == 1) { - fCtsdeltalength = u; - } else if (sscanf(line, " de-interleavebuffersize = %u", &u) == 1) { - fDe_interleavebuffersize = u; - } else if (sscanf(line, " dtsdeltalength = %u", &u) == 1) { - fDtsdeltalength = u; - } else if (sscanf(line, " indexdeltalength = %u", &u) == 1) { - fIndexdeltalength = u; - } else if (sscanf(line, " indexlength = %u", &u) == 1) { - fIndexlength = u; - } else if (sscanf(line, " interleaving = %u", &u) == 1) { - fInterleaving = u; - } else if (sscanf(line, " maxdisplacement = %u", &u) == 1) { - fMaxdisplacement = u; - } else if (sscanf(line, " objecttype = %u", &u) == 1) { - fObjecttype = u; - } else if (sscanf(line, " octet-align = %u", &u) == 1) { - fOctetalign = u; - } else if (sscanf(line, " profile-level-id = %u", &u) == 1) { - fProfile_level_id = u; - } else if (sscanf(line, " robust-sorting = %u", &u) == 1) { - fRobustsorting = u; - } else if (sscanf(line, " sizelength = %u", &u) == 1) { - fSizelength = u; - } else if (sscanf(line, " streamstateindication = %u", &u) == 1) { - fStreamstateindication = u; - } else if (sscanf(line, " streamtype = %u", &u) == 1) { - fStreamtype = u; - } else if (sscanf(line, " cpresent = %u", &u) == 1) { - fCpresent = u != 0; - } else if (sscanf(line, " randomaccessindication = %u", &u) == 1) { - fRandomaccessindication = u != 0; - } else if (sscanf(line, " config = %[^; \t\r\n]", valueStr) == 1) { - delete[] fConfig; fConfig = strDup(valueStr); - } else if (sscanf(line, " mode = %[^; \t\r\n]", valueStr) == 1) { - delete[] fMode; fMode = strDup(valueStr); - } else if (sscanf(sdpLine, " sprop-parameter-sets = %[^; \t\r\n]", valueStr) == 1) { - // Note: We used "sdpLine" here, because the value is case-sensitive. - delete[] fSpropParameterSets; fSpropParameterSets = strDup(valueStr); - } else { - // Some of the above parameters are Boolean. Check whether the parameter - // names appear alone, without a "= 1" at the end: - if (sscanf(line, " %[^; \t\r\n]", valueStr) == 1) { - if (strcmp(valueStr, "octet-align") == 0) { - fOctetalign = 1; - } else if (strcmp(valueStr, "cpresent") == 0) { - fCpresent = True; - } else if (strcmp(valueStr, "crc") == 0) { - fCRC = 1; - } else if (strcmp(valueStr, "robust-sorting") == 0) { - fRobustsorting = 1; - } else if (strcmp(valueStr, "randomaccessindication") == 0) { - fRandomaccessindication = True; - } - } - } - delete[] valueStr; - - // Move to the next parameter assignment string: - while (*line != '\0' && *line != '\r' && *line != '\n' - && *line != ';') ++line; - while (*line == ';') ++line; - - // Do the same with sdpLine; needed for finding case sensitive values: - while (*sdpLine != '\0' && *sdpLine != '\r' && *sdpLine != '\n' - && *sdpLine != ';') ++sdpLine; - while (*sdpLine == ';') ++sdpLine; - } - delete[] lineCopy; - return True; - } while (0); - - return False; -} - -Boolean MediaSubsession -::parseSDPAttribute_source_filter(char const* sdpLine) { - return parseSourceFilterAttribute(sdpLine, fSourceFilterAddr); -} - -Boolean MediaSubsession::parseSDPAttribute_x_mct_slap(char const* sdpLine) { - // Check for a "a=x-mct-slap: " line: - Boolean parseSuccess = False; - - int slapSessionId; - int slapStagger; - if (sscanf(sdpLine, "a=x-mct-slap: %d %d", - &slapSessionId, &slapStagger) == 2) { - parseSuccess = True; - fMCT_SLAP_SessionId = slapSessionId; - fMCT_SLAP_Stagger = (unsigned)slapStagger; - } - - return parseSuccess; -} - -Boolean MediaSubsession::parseSDPAttribute_x_dimensions(char const* sdpLine) { - // Check for a "a=x-dimensions:," line: - Boolean parseSuccess = False; - - int width, height; - if (sscanf(sdpLine, "a=x-dimensions:%d,%d", &width, &height) == 2) { - parseSuccess = True; - fVideoWidth = (unsigned short)width; - fVideoHeight = (unsigned short)height; - } - - return parseSuccess; -} - -Boolean MediaSubsession::parseSDPAttribute_x_framerate(char const* sdpLine) { - // Check for a "a=x-framerate:" line: - Boolean parseSuccess = False; - - int rate; - if (sscanf(sdpLine, "a=x-framerate:%d", &rate) == 1) { - parseSuccess = True; - fVideoFPS = (unsigned)rate; - } - - return parseSuccess; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MediaSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MediaSink.cpp deleted file mode 100644 index 9740e652310..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MediaSink.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 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()); - nextTask() = NULL; - - fSource = NULL; // indicates that we can be played again - fAfterFunc = NULL; -} - -void MediaSink::onSourceClosure(void* clientData) { - MediaSink* sink = (MediaSink*)clientData; - sink->fSource = NULL; // indicates that we can be played again - if (sink->fAfterFunc != NULL) { - (*(sink->fAfterFunc))(sink->fAfterClientData); - } -} - -Boolean MediaSink::isRTPSink() const { - return False; // default implementation -} - -////////// OutPacketBuffer ////////// - -unsigned OutPacketBuffer::maxSize = 60000; // by default - -OutPacketBuffer::OutPacketBuffer(unsigned preferredPacketSize, - unsigned maxPacketSize) - : fPreferred(preferredPacketSize), fMax(maxPacketSize), - fOverflowDataSize(0) { - unsigned maxNumPackets = (maxSize + (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(unsigned word) { - unsigned 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(unsigned word, unsigned toPosition) { - unsigned 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); -} - -unsigned OutPacketBuffer::extractWord(unsigned fromPosition) { - unsigned 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; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MediaSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MediaSource.cpp deleted file mode 100644 index eb65321df10..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MediaSource.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Media Sources -// Implementation - -#include "MediaSource.hh" - -////////// MediaSource ////////// - -MediaSource::MediaSource(UsageEnvironment& env) - : Medium(env) { -} - -MediaSource::~MediaSource() { -} - -Boolean MediaSource::isSource() const { - return True; -} - -char const* MediaSource::MIMEtype() const { - return "application/OCTET-STREAM"; // default type -} - -Boolean MediaSource::isFramedSource() const { - return False; // default implementation -} -Boolean MediaSource::isRTPSource() const { - return False; // default implementation -} -Boolean MediaSource::isMPEG1or2VideoStreamFramer() const { - return False; // default implementation -} -Boolean MediaSource::isMPEG4VideoStreamFramer() const { - return False; // default implementation -} -Boolean MediaSource::isJPEGVideoSource() const { - return False; // default implementation -} -Boolean MediaSource::isAMRAudioSource() const { - return False; // default implementation -} - -Boolean MediaSource::lookupByName(UsageEnvironment& env, - char const* sourceName, - MediaSource*& resultSource) { - resultSource = NULL; // unless we succeed - - Medium* medium; - if (!Medium::lookupByName(env, sourceName, medium)) return False; - - if (!medium->isSource()) { - env.setResultMsg(sourceName, " is not a media source"); - return False; - } - - resultSource = (MediaSource*)medium; - return True; -} - -void MediaSource::getAttributes() const { - // Default implementation - envir().setResultMsg(""); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MultiFramedRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MultiFramedRTPSink.cpp deleted file mode 100644 index 3e3c27b8344..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MultiFramedRTPSink.cpp +++ /dev/null @@ -1,396 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for a common kind of payload format: Those which pack multiple, -// complete codec frames (as many as possible) into each RTP packet. -// Implementation - -#include "MultiFramedRTPSink.hh" -#include "GroupsockHelper.hh" - -////////// MultiFramedRTPSink ////////// - -void MultiFramedRTPSink::setPacketSizes(unsigned preferredPacketSize, - unsigned maxPacketSize) { - if (preferredPacketSize > maxPacketSize || preferredPacketSize == 0) return; - // sanity check - - delete fOutBuf; - fOutBuf = new OutPacketBuffer(preferredPacketSize, maxPacketSize); -} - -MultiFramedRTPSink::MultiFramedRTPSink(UsageEnvironment& env, - Groupsock* rtpGS, - unsigned char rtpPayloadType, - unsigned rtpTimestampFrequency, - char const* rtpPayloadFormatName, - unsigned numChannels) - : RTPSink(env, rtpGS, rtpPayloadType, rtpTimestampFrequency, - rtpPayloadFormatName, numChannels), - fOutBuf(NULL), fCurFragmentationOffset(0), fPreviousFrameEndedFragmentation(False) { - setPacketSizes(1000, 1448); - // Default max packet size (1500, minus allowance for IP, UDP, UMTP headers) - // (Also, make it a multiple of 4 bytes, just in case that matters.) -} - -MultiFramedRTPSink::~MultiFramedRTPSink() { - delete fOutBuf; -} - -void MultiFramedRTPSink -::doSpecialFrameHandling(unsigned /*fragmentationOffset*/, - unsigned char* /*frameStart*/, - unsigned /*numBytesInFrame*/, - struct timeval frameTimestamp, - unsigned /*numRemainingBytes*/) { - // default implementation: If this is the first frame in the packet, - // use its timestamp for the RTP timestamp: - if (isFirstFrameInPacket()) { - setTimestamp(frameTimestamp); - } -} - -Boolean MultiFramedRTPSink::allowFragmentationAfterStart() const { - return False; // by default -} - -Boolean MultiFramedRTPSink::allowOtherFramesAfterLastFragment() const { - return False; // by default -} - -Boolean MultiFramedRTPSink -::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - return True; // by default -} - -unsigned MultiFramedRTPSink::specialHeaderSize() const { - // default implementation: Assume no special header: - return 0; -} - -unsigned MultiFramedRTPSink::frameSpecificHeaderSize() const { - // default implementation: Assume no frame-specific header: - return 0; -} - -void MultiFramedRTPSink::setMarkerBit() { - unsigned rtpHdr = fOutBuf->extractWord(0); - rtpHdr |= 0x00800000; - fOutBuf->insertWord(rtpHdr, 0); -} - -void MultiFramedRTPSink::setTimestamp(struct timeval timestamp) { - // First, convert the timestamp to a 32-bit RTP timestamp: - fCurrentTimestamp = convertToRTPTimestamp(timestamp); - - // Then, insert it into the RTP packet: - fOutBuf->insertWord(fCurrentTimestamp, fTimestampPosition); -} - -void MultiFramedRTPSink::setSpecialHeaderWord(unsigned word, - unsigned wordPosition) { - fOutBuf->insertWord(word, fSpecialHeaderPosition + 4*wordPosition); -} - -void MultiFramedRTPSink::setSpecialHeaderBytes(unsigned char const* bytes, - unsigned numBytes, - unsigned bytePosition) { - fOutBuf->insert(bytes, numBytes, fSpecialHeaderPosition + bytePosition); -} - -void MultiFramedRTPSink::setFrameSpecificHeaderWord(unsigned word, - unsigned wordPosition) { - fOutBuf->insertWord(word, fCurFrameSpecificHeaderPosition + 4*wordPosition); -} - -void MultiFramedRTPSink::setFrameSpecificHeaderBytes(unsigned char const* bytes, - unsigned numBytes, - unsigned bytePosition) { - fOutBuf->insert(bytes, numBytes, fCurFrameSpecificHeaderPosition + bytePosition); -} - -Boolean MultiFramedRTPSink::continuePlaying() { - // Send the first packet. - // (This will also schedule any future sends.) - buildAndSendPacket(True); - return True; -} - -void MultiFramedRTPSink::stopPlaying() { - fOutBuf->resetPacketStart(); - fOutBuf->resetOffset(); - fOutBuf->resetOverflowData(); - - // Then call the default "stopPlaying()" function: - MediaSink::stopPlaying(); -} - -void MultiFramedRTPSink::buildAndSendPacket(Boolean isFirstPacket) { - fIsFirstPacket = isFirstPacket; - - // Set up the RTP header: - unsigned rtpHdr = 0x80000000; // RTP version 2 - rtpHdr |= (fRTPPayloadType<<16); - rtpHdr |= fSeqNo; // sequence number - fOutBuf->enqueueWord(rtpHdr); - - // Note where the RTP timestamp will go. - // (We can't fill this in until we start packing payload frames.) - fTimestampPosition = fOutBuf->curPacketSize(); - fOutBuf->skipBytes(4); // leave a hole for the timestamp - - fOutBuf->enqueueWord(SSRC()); - - // Allow for a special, payload-format-specific header following the - // RTP header: - fSpecialHeaderPosition = fOutBuf->curPacketSize(); - fSpecialHeaderSize = specialHeaderSize(); - fOutBuf->skipBytes(fSpecialHeaderSize); - - // Begin packing as many (complete) frames into the packet as we can: - fTotalFrameSpecificHeaderSizes = 0; - fNoFramesLeft = False; - fNumFramesUsedSoFar = 0; - packFrame(); -} - -void MultiFramedRTPSink::packFrame() { - // Get the next frame. - - // First, see if we have an overflow frame that was too big for the last pkt - if (fOutBuf->haveOverflowData()) { - // Use this frame before reading a new one from the source - unsigned frameSize = fOutBuf->overflowDataSize(); - struct timeval presentationTime = fOutBuf->overflowPresentationTime(); - unsigned durationInMicroseconds = fOutBuf->overflowDurationInMicroseconds(); - fOutBuf->useOverflowData(); - - afterGettingFrame1(frameSize, 0, presentationTime, durationInMicroseconds); - } else { - // Normal case: we need to read a new frame from the source - if (fSource == NULL) return; - - fCurFrameSpecificHeaderPosition = fOutBuf->curPacketSize(); - fCurFrameSpecificHeaderSize = frameSpecificHeaderSize(); - fOutBuf->skipBytes(fCurFrameSpecificHeaderSize); - fTotalFrameSpecificHeaderSizes += fCurFrameSpecificHeaderSize; - - fSource->getNextFrame(fOutBuf->curPtr(), fOutBuf->totalBytesAvailable(), - afterGettingFrame, this, ourHandleClosure, this); - } -} - -void MultiFramedRTPSink -::afterGettingFrame(void* clientData, unsigned numBytesRead, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - MultiFramedRTPSink* sink = (MultiFramedRTPSink*)clientData; - sink->afterGettingFrame1(numBytesRead, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -void MultiFramedRTPSink -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - if (fIsFirstPacket) { - // Record the fact that we're starting to play now: - gettimeofday(&fNextSendTime, NULL); - } - - if (numTruncatedBytes > 0) { - unsigned const bufferSize = fOutBuf->totalBytesAvailable(); - unsigned newMaxSize = frameSize + numTruncatedBytes; - envir() << "MultiFramedRTPSink::afterGettingFrame1(): The input frame data was too large for our buffer size (" - << bufferSize << "). " - << numTruncatedBytes << " bytes of trailing data was dropped! Correct this by increasing \"OutPacketBuffer::maxSize\" to at least " - << newMaxSize << ", *before* creating this 'RTPSink'. (Current value is " - << OutPacketBuffer::maxSize << ".)\n"; - } - unsigned curFragmentationOffset = fCurFragmentationOffset; - unsigned numFrameBytesToUse = frameSize; - unsigned overflowBytes = 0; - - // If we have already packed one or more frames into this packet, - // check whether this new frame is eligible to be packed after them. - // (This is independent of whether the packet has enough room for this - // new frame; that check comes later.) - if (fNumFramesUsedSoFar > 0) { - if ((fPreviousFrameEndedFragmentation - && !allowOtherFramesAfterLastFragment()) - || !frameCanAppearAfterPacketStart(fOutBuf->curPtr(), frameSize)) { - // Save away this frame for next time: - numFrameBytesToUse = 0; - fOutBuf->setOverflowData(fOutBuf->curPacketSize(), frameSize, - presentationTime, durationInMicroseconds); - } - } - fPreviousFrameEndedFragmentation = False; - - if (numFrameBytesToUse > 0) { - // Check whether this frame overflows the packet - if (fOutBuf->wouldOverflow(frameSize)) { - // Don't use this frame now; instead, save it as overflow data, and - // send it in the next packet instead. However, if the frame is too - // big to fit in a packet by itself, then we need to fragment it (and - // use some of it in this packet, if the payload format permits this.) - if (isTooBigForAPacket(frameSize) - && (fNumFramesUsedSoFar == 0 || allowFragmentationAfterStart())) { - // We need to fragment this frame, and use some of it now: - overflowBytes = fOutBuf->numOverflowBytes(frameSize); - numFrameBytesToUse -= overflowBytes; - fCurFragmentationOffset += numFrameBytesToUse; - } else { - // We don't use any of this frame now: - overflowBytes = frameSize; - numFrameBytesToUse = 0; - } - fOutBuf->setOverflowData(fOutBuf->curPacketSize() + numFrameBytesToUse, - overflowBytes, presentationTime, - durationInMicroseconds); - } else if (fCurFragmentationOffset > 0) { - // This is the last fragment of a frame that was fragmented over - // more than one packet. Do any special handling for this case: - fCurFragmentationOffset = 0; - fPreviousFrameEndedFragmentation = True; - } - } - - if (numFrameBytesToUse == 0) { - // Send our packet now, because we have filled it up: - sendPacketIfNecessary(); - } else { - // Use this frame in our outgoing packet: - - // Here's where any payload format specific processing gets done: - doSpecialFrameHandling(curFragmentationOffset, fOutBuf->curPtr(), - numFrameBytesToUse, presentationTime, - overflowBytes); - - fOutBuf->increment(numFrameBytesToUse); - ++fNumFramesUsedSoFar; - - // Update the time at which the next packet should be sent, based - // on the duration of the frame that we just packed into it. - // However, if this frame has overflow data remaining, then don't - // count its duration yet. - if (overflowBytes == 0) { - fNextSendTime.tv_usec += durationInMicroseconds; - fNextSendTime.tv_sec += fNextSendTime.tv_usec/1000000; - fNextSendTime.tv_usec %= 1000000; - } - - // Send our packet now if (i) it's already at our preferred size, or - // (ii) (heuristic) another frame of the same size as the one we just - // read would overflow the packet, or - // (iii) it contains the last fragment of a fragmented frame, and we - // don't allow anything else to follow this or - // (iv) one frame per packet is allowed: - if (fOutBuf->isPreferredSize() - || fOutBuf->wouldOverflow(numFrameBytesToUse) - || (fPreviousFrameEndedFragmentation && - !allowOtherFramesAfterLastFragment()) - || !frameCanAppearAfterPacketStart(fOutBuf->curPtr() - frameSize, - frameSize) ) { - // The packet is ready to be sent now - sendPacketIfNecessary(); - } else { - // There's room for more frames; try getting another: - packFrame(); - } - } -} - -static unsigned const rtpHeaderSize = 12; - -Boolean MultiFramedRTPSink::isTooBigForAPacket(unsigned numBytes) const { - // Check whether a 'numBytes'-byte frame - together with a RTP header and - // (possible) special headers - would be too big for an output packet: - // (Later allow for RTP extension header!) ##### - numBytes += rtpHeaderSize + specialHeaderSize() + frameSpecificHeaderSize(); - return fOutBuf->isTooBigForAPacket(numBytes); -} - -void MultiFramedRTPSink::sendPacketIfNecessary() { - if (fNumFramesUsedSoFar > 0) { - // Send the packet: -#ifdef TEST_LOSS - if ((our_random()%10) != 0) // simulate 10% packet loss ##### -#endif - fRTPInterface.sendPacket(fOutBuf->packet(), fOutBuf->curPacketSize()); - ++fPacketCount; - fTotalOctetCount += fOutBuf->curPacketSize(); - fOctetCount += fOutBuf->curPacketSize() - - rtpHeaderSize - fSpecialHeaderSize - fTotalFrameSpecificHeaderSizes; - - ++fSeqNo; // for next time - } - - if (fOutBuf->haveOverflowData() - && fOutBuf->totalBytesAvailable() > fOutBuf->totalBufferSize()/2) { - // Efficiency hack: Reset the packet start pointer to just in front of - // the overflow data (allowing for the RTP header and special headers), - // so that we probably don't have to "memmove()" the overflow data - // into place when building the next packet: - unsigned newPacketStart = fOutBuf->curPacketSize() - - (rtpHeaderSize + fSpecialHeaderSize + frameSpecificHeaderSize()); - fOutBuf->adjustPacketStart(newPacketStart); - } else { - // Normal case: Reset the packet start pointer back to the start: - fOutBuf->resetPacketStart(); - } - fOutBuf->resetOffset(); - fNumFramesUsedSoFar = 0; - - if (fNoFramesLeft) { - // We're done: - onSourceClosure(this); - } else { - // We have more frames left to send. Figure out when the next frame - // is due to start playing, then make sure that we wait this long before - // sending the next packet. - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - int uSecondsToGo; - if (fNextSendTime.tv_sec < timeNow.tv_sec) { - uSecondsToGo = 0; // prevents integer underflow if too far behind - } else { - uSecondsToGo = (fNextSendTime.tv_sec - timeNow.tv_sec)*1000000 - + (fNextSendTime.tv_usec - timeNow.tv_usec); - } - - // Delay this amount of time: - nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToGo, - (TaskFunc*)sendNext, this); - } -} - -// The following is called after each delay between packet sends: -void MultiFramedRTPSink::sendNext(void* firstArg) { - MultiFramedRTPSink* sink = (MultiFramedRTPSink*)firstArg; - sink->buildAndSendPacket(False); -} - -void MultiFramedRTPSink::ourHandleClosure(void* clientData) { - MultiFramedRTPSink* sink = (MultiFramedRTPSink*)clientData; - // There are no frames left, but we may have a partially built packet - // to send - sink->fNoFramesLeft = True; - sink->sendPacketIfNecessary(); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/MultiFramedRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/MultiFramedRTPSource.cpp deleted file mode 100644 index db5d57abf8b..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/MultiFramedRTPSource.cpp +++ /dev/null @@ -1,543 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP source for a common kind of payload format: Those that pack multiple, -// complete codec frames (as many as possible) into each RTP packet. -// Implementation - -#include "MultiFramedRTPSource.hh" -#include "GroupsockHelper.hh" -#include - -////////// ReorderingPacketBuffer definition ////////// - -class ReorderingPacketBuffer { -public: - ReorderingPacketBuffer(BufferedPacketFactory* packetFactory); - virtual ~ReorderingPacketBuffer(); - void reset(); - - BufferedPacket* getFreePacket(MultiFramedRTPSource* ourSource); - void storePacket(BufferedPacket* bPacket); - BufferedPacket* getNextCompletedPacket(Boolean& packetLossPreceded); - void releaseUsedPacket(BufferedPacket* packet); - void freePacket(BufferedPacket* packet) { - if (packet != fSavedPacket) delete packet; - } - - void setThresholdTime(unsigned uSeconds) { fThresholdTime = uSeconds; } - -private: - BufferedPacketFactory* fPacketFactory; - unsigned fThresholdTime; // uSeconds - Boolean fHaveSeenFirstPacket; // used to set initial "fNextExpectedSeqNo" - unsigned short fNextExpectedSeqNo; - BufferedPacket* fHeadPacket; - BufferedPacket* fSavedPacket; - // to avoid calling new/free in the common case -}; - - -////////// MultiFramedRTPSource implementation ////////// - -MultiFramedRTPSource -::MultiFramedRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - BufferedPacketFactory* packetFactory) - : RTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency) { - reset(); - fReorderingBuffer = new ReorderingPacketBuffer(packetFactory); - - // Try to use a big receive buffer for RTP: - increaseReceiveBufferTo(env, RTPgs->socketNum(), 50*1024); -} - -void MultiFramedRTPSource::reset() { - fCurrentPacketBeginsFrame = True; // by default - fCurrentPacketCompletesFrame = True; // by default - fAreDoingNetworkReads = False; - fNeedDelivery = False; - fPacketLossInFragmentedFrame = False; -} - -MultiFramedRTPSource::~MultiFramedRTPSource() { - fRTPInterface.stopNetworkReading(); - delete fReorderingBuffer; -} - -Boolean MultiFramedRTPSource -::processSpecialHeader(BufferedPacket* /*packet*/, - unsigned& resultSpecialHeaderSize) { - // Default implementation: Assume no special header: - resultSpecialHeaderSize = 0; - return True; -} - -Boolean MultiFramedRTPSource -::packetIsUsableInJitterCalculation(unsigned char* /*packet*/, - unsigned /*packetSize*/) { - // Default implementation: - return True; -} - -void MultiFramedRTPSource::doStopGettingFrames() { - fRTPInterface.stopNetworkReading(); - fReorderingBuffer->reset(); - reset(); -} - -void MultiFramedRTPSource::doGetNextFrame() { - if (!fAreDoingNetworkReads) { - // Turn on background read handling of incoming packets: - fAreDoingNetworkReads = True; - TaskScheduler::BackgroundHandlerProc* handler - = (TaskScheduler::BackgroundHandlerProc*)&networkReadHandler; - fRTPInterface.startNetworkReading(handler); - } - - fSavedTo = fTo; - fSavedMaxSize = fMaxSize; - fFrameSize = 0; // for now - fNeedDelivery = True; - doGetNextFrame1(); -} - -void MultiFramedRTPSource::doGetNextFrame1() { - while (fNeedDelivery) { - // If we already have packet data available, then deliver it now. - Boolean packetLossPrecededThis; - BufferedPacket* nextPacket - = fReorderingBuffer->getNextCompletedPacket(packetLossPrecededThis); - if (nextPacket == NULL) break; - - fNeedDelivery = False; - - if (nextPacket->useCount() == 0) { - // Before using the packet, check whether it has a special header - // that needs to be processed: - unsigned specialHeaderSize; - if (!processSpecialHeader(nextPacket, specialHeaderSize)) { - // Something's wrong with the header; reject the packet: - fReorderingBuffer->releaseUsedPacket(nextPacket); - fNeedDelivery = True; - break; - } - nextPacket->skip(specialHeaderSize); - } - - // Check whether we're part of a multi-packet frame, and whether - // there was packet loss that would render this packet unusable: - if (fCurrentPacketBeginsFrame) { - if (packetLossPrecededThis || fPacketLossInFragmentedFrame) { - // We didn't get all of the previous frame. - // Forget any data that we used from it: - fTo = fSavedTo; fMaxSize = fSavedMaxSize; - fFrameSize = 0; - } - fPacketLossInFragmentedFrame = False; - } else if (packetLossPrecededThis) { - // We're in a multi-packet frame, with preceding packet loss - fPacketLossInFragmentedFrame = True; - } - if (fPacketLossInFragmentedFrame) { - // This packet is unusable; reject it: - fReorderingBuffer->releaseUsedPacket(nextPacket); - fNeedDelivery = True; - break; - } - - // The packet is usable. Deliver all or part of it to our caller: - unsigned frameSize; - nextPacket->use(fTo, fMaxSize, frameSize, fNumTruncatedBytes, - fCurPacketRTPSeqNum, fCurPacketRTPTimestamp, - fPresentationTime, fCurPacketHasBeenSynchronizedUsingRTCP, - fCurPacketMarkerBit); - fFrameSize += frameSize; - - if (!nextPacket->hasUsableData()) { - // We're completely done with this packet now - fReorderingBuffer->releaseUsedPacket(nextPacket); - } - - if (fCurrentPacketCompletesFrame || fNumTruncatedBytes > 0) { - // We have all the data that the client wants. - if (fNumTruncatedBytes > 0) { - envir() << "MultiFramedRTPSource::doGetNextFrame1(): The total received frame size exceeds the client's buffer size (" - << fSavedMaxSize << "). " - << fNumTruncatedBytes << " bytes of trailing data will be dropped!\n"; - } - // Call our own 'after getting' function. Because we're preceded - // by a network read, we can call this directly, without risking - // infinite recursion. - afterGetting(this); - } else { - // This packet contained fragmented data, and does not complete - // the data that the client wants. Keep getting data: - fTo += frameSize; fMaxSize -= frameSize; - fNeedDelivery = True; - } - } -} - -void MultiFramedRTPSource -::setPacketReorderingThresholdTime(unsigned uSeconds) { - fReorderingBuffer->setThresholdTime(uSeconds); -} - -#define ADVANCE(n) do { bPacket->skip(n); } while (0) - -void MultiFramedRTPSource::networkReadHandler(MultiFramedRTPSource* source, - int /*mask*/) { - // Get a free BufferedPacket descriptor to hold the new network packet: - BufferedPacket* bPacket - = source->fReorderingBuffer->getFreePacket(source); - - // Read the network packet, and perform sanity checks on the RTP header: - Boolean readSuccess = False; - do { - if (!bPacket->fillInData(source->fRTPInterface)) break; -#ifdef TEST_LOSS - source->setPacketReorderingThresholdTime(0); - // don't wait for 'lost' packets to arrive out-of-order later - if ((our_random()%10) == 0) break; // simulate 10% packet loss -#endif - - // Check for the 12-byte RTP header: - if (bPacket->dataSize() < 12) break; - unsigned rtpHdr = ntohl(*(unsigned*)(bPacket->data())); ADVANCE(4); - Boolean rtpMarkerBit = (rtpHdr&0x00800000) >> 23; - unsigned rtpTimestamp = ntohl(*(unsigned*)(bPacket->data()));ADVANCE(4); - unsigned rtpSSRC = ntohl(*(unsigned*)(bPacket->data())); ADVANCE(4); - - // Check the RTP version number (it should be 2): - if ((rtpHdr&0xC0000000) != 0x80000000) break; - - // Skip over any CSRC identifiers in the header: - unsigned cc = (rtpHdr>>24)&0xF; - if (bPacket->dataSize() < cc) break; - ADVANCE(cc*4); - - // Check for (& ignore) any RTP header extension - if (rtpHdr&0x10000000) { - if (bPacket->dataSize() < 4) break; - unsigned extHdr = ntohl(*(unsigned*)(bPacket->data())); ADVANCE(4); - unsigned remExtSize = 4*(extHdr&0xFFFF); - if (bPacket->dataSize() < remExtSize) break; - ADVANCE(remExtSize); - } - - // Discard any padding bytes: - if (rtpHdr&0x20000000) { - if (bPacket->dataSize() == 0) break; - unsigned numPaddingBytes - = (unsigned)(bPacket->data())[bPacket->dataSize()-1]; - if (bPacket->dataSize() < numPaddingBytes) break; - bPacket->removePadding(numPaddingBytes); - } - // Check the Payload Type. - if ((unsigned char)((rtpHdr&0x007F0000)>>16) - != source->rtpPayloadFormat()) { - break; - } - - // The rest of the packet is the usable data. Record and save it: - source->fLastReceivedSSRC = rtpSSRC; - unsigned short rtpSeqNo = (unsigned short)(rtpHdr&0xFFFF); - Boolean usableInJitterCalculation - = source->packetIsUsableInJitterCalculation((bPacket->data()), - bPacket->dataSize()); - struct timeval presentationTime; // computed by: - Boolean hasBeenSyncedUsingRTCP; // computed by: - source->receptionStatsDB() - .noteIncomingPacket(rtpSSRC, rtpSeqNo, rtpTimestamp, - source->timestampFrequency(), - usableInJitterCalculation, presentationTime, - hasBeenSyncedUsingRTCP, bPacket->dataSize()); - - // Fill in the rest of the packet descriptor, and store it: - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - bPacket->assignMiscParams(rtpSeqNo, rtpTimestamp, presentationTime, - hasBeenSyncedUsingRTCP, rtpMarkerBit, - timeNow); - source->fReorderingBuffer->storePacket(bPacket); - - readSuccess = True; - } while (0); - if (!readSuccess) source->fReorderingBuffer->freePacket(bPacket); - - source->doGetNextFrame1(); - // If we didn't get proper data this time, we'll get another chance -} - - -////////// BufferedPacket and BufferedPacketFactory implementation ///// - -#define MAX_PACKET_SIZE 10000 - -BufferedPacket::BufferedPacket() - : fPacketSize(MAX_PACKET_SIZE), - fBuf(new unsigned char[MAX_PACKET_SIZE]), - fNextPacket(NULL) { -} - -BufferedPacket::~BufferedPacket() { - delete fNextPacket; - delete[] fBuf; -} - -void BufferedPacket::reset() { - fHead = fTail = 0; - fUseCount = 0; -} - -// The following function has been deprecated: -unsigned BufferedPacket -::nextEnclosedFrameSize(unsigned char*& /*framePtr*/, unsigned dataSize) { - // By default, use the entire buffered data, even though it may consist - // of more than one frame, on the assumption that the client doesn't - // care. (This is more efficient than delivering a frame at a time) - return dataSize; -} - -void BufferedPacket -::getNextEnclosedFrameParameters(unsigned char*& framePtr, unsigned dataSize, - unsigned& frameSize, - unsigned& frameDurationInMicroseconds) { - // By default, use the entire buffered data, even though it may consist - // of more than one frame, on the assumption that the client doesn't - // care. (This is more efficient than delivering a frame at a time) - - // For backwards-compatibilty with existing uses of (the now deprecated) - // "nextEnclosedFrameSize()", call that function to implement this one: - frameSize = nextEnclosedFrameSize(framePtr, dataSize); - - frameDurationInMicroseconds = 0; // by default. Subclasses should correct this. -} - -Boolean BufferedPacket::fillInData(RTPInterface& rtpInterface) { - reset(); - - unsigned numBytesRead; - struct sockaddr_in fromAddress; - if (!rtpInterface.handleRead(&fBuf[fTail], fPacketSize-fTail, numBytesRead, - fromAddress)) { - return False; - } - fTail += numBytesRead; - return True; -} - -void BufferedPacket -::assignMiscParams(unsigned short rtpSeqNo, unsigned rtpTimestamp, - struct timeval presentationTime, - Boolean hasBeenSyncedUsingRTCP, Boolean rtpMarkerBit, - struct timeval timeReceived) { - fRTPSeqNo = rtpSeqNo; - fRTPTimestamp = rtpTimestamp; - fPresentationTime = presentationTime; - fHasBeenSyncedUsingRTCP = hasBeenSyncedUsingRTCP; - fRTPMarkerBit = rtpMarkerBit; - fTimeReceived = timeReceived; -} - -void BufferedPacket::skip(unsigned numBytes) { - fHead += numBytes; - if (fHead > fTail) fHead = fTail; -} - -void BufferedPacket::removePadding(unsigned numBytes) { - if (numBytes > fTail-fHead) numBytes = fTail-fHead; - fTail -= numBytes; -} - -void BufferedPacket::appendData(unsigned char* newData, unsigned numBytes) { - if (numBytes > fPacketSize-fTail) numBytes = fPacketSize - fTail; - memmove(&fBuf[fTail], newData, numBytes); - fTail += numBytes; -} - -void BufferedPacket::use(unsigned char* to, unsigned toSize, - unsigned& bytesUsed, unsigned& bytesTruncated, - unsigned short& rtpSeqNo, unsigned& rtpTimestamp, - struct timeval& presentationTime, - Boolean& hasBeenSyncedUsingRTCP, - Boolean& rtpMarkerBit) { - unsigned char* origFramePtr = &fBuf[fHead]; - unsigned char* newFramePtr = origFramePtr; // may change in the call below - unsigned frameSize, frameDurationInMicroseconds; - getNextEnclosedFrameParameters(newFramePtr, fTail - fHead, - frameSize, frameDurationInMicroseconds); - if (frameSize > toSize) { - bytesTruncated = frameSize - toSize; - bytesUsed = toSize; - } else { - bytesTruncated = 0; - bytesUsed = frameSize; - } - - memmove(to, newFramePtr, bytesUsed); - fHead += (newFramePtr - origFramePtr) + frameSize; - ++fUseCount; - - rtpSeqNo = fRTPSeqNo; - rtpTimestamp = fRTPTimestamp; - presentationTime = fPresentationTime; - hasBeenSyncedUsingRTCP = fHasBeenSyncedUsingRTCP; - rtpMarkerBit = fRTPMarkerBit; - - // Update "fPresentationTime" for the next enclosed frame (if any): - fPresentationTime.tv_usec += frameDurationInMicroseconds; - if (fPresentationTime.tv_usec >= 1000000) { - fPresentationTime.tv_sec += fPresentationTime.tv_usec/1000000; - fPresentationTime.tv_usec = fPresentationTime.tv_usec%1000000; - } -} - -BufferedPacketFactory::BufferedPacketFactory() { -} - -BufferedPacketFactory::~BufferedPacketFactory() { -} - -BufferedPacket* BufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* /*ourSource*/) { - return new BufferedPacket; -} - - -////////// ReorderingPacketBuffer implementation ////////// - -ReorderingPacketBuffer -::ReorderingPacketBuffer(BufferedPacketFactory* packetFactory) - : fThresholdTime(100000) /* default reordering threshold: 100 ms */, - fHaveSeenFirstPacket(False), fHeadPacket(NULL), fSavedPacket(NULL) { - fPacketFactory = (packetFactory == NULL) - ? (new BufferedPacketFactory) - : packetFactory; -} - -ReorderingPacketBuffer::~ReorderingPacketBuffer() { - reset(); - delete fPacketFactory; -} - -void ReorderingPacketBuffer::reset() { - if (fHeadPacket == NULL) { - delete fSavedPacket; - } else { - delete fHeadPacket; // will also delete fSavedPacket, because it's on the list - } - fHaveSeenFirstPacket = False; - fHeadPacket = NULL; - fSavedPacket = NULL; -} - -BufferedPacket* ReorderingPacketBuffer -::getFreePacket(MultiFramedRTPSource* ourSource) { - if (fSavedPacket == NULL) { // we're being called for the first time - fSavedPacket = fPacketFactory->createNewPacket(ourSource); - } - - return fHeadPacket == NULL - ? fSavedPacket - : fPacketFactory->createNewPacket(ourSource); -} - -void ReorderingPacketBuffer::storePacket(BufferedPacket* bPacket) { - unsigned short rtpSeqNo = bPacket->rtpSeqNo(); - - if (!fHaveSeenFirstPacket) { - fNextExpectedSeqNo = rtpSeqNo; // initialization - fHaveSeenFirstPacket = True; - } - - // Ignore this packet if its sequence number is less than the one - // that we're looking for (in this case, it's been excessively delayed). - // (But (sanity check) if the new packet's sequence number is a *lot* - // less, then accept it anyway.) - unsigned short const seqNoThreshold = 100; - if (seqNumLT(rtpSeqNo, fNextExpectedSeqNo) - && seqNumLT(fNextExpectedSeqNo, rtpSeqNo+seqNoThreshold)) { - return; - } - - // Figure out where the new packet will be stored in the queue: - BufferedPacket* beforePtr = NULL; - BufferedPacket* afterPtr = fHeadPacket; - while (afterPtr != NULL) { - if (seqNumLT(rtpSeqNo, afterPtr->rtpSeqNo())) break; // it comes here - if (rtpSeqNo == afterPtr->rtpSeqNo()) { - // This is a duplicate packet - ignore it - return; - } - - beforePtr = afterPtr; - afterPtr = afterPtr->nextPacket(); - } - - // Link our new packet between "beforePtr" and "afterPtr": - bPacket->nextPacket() = afterPtr; - if (beforePtr == NULL) { - fHeadPacket = bPacket; - } else { - beforePtr->nextPacket() = bPacket; - } -} - -void ReorderingPacketBuffer::releaseUsedPacket(BufferedPacket* packet) { - // ASSERT: packet == fHeadPacket - // ASSERT: fNextExpectedSeqNo == packet->rtpSeqNo() - ++fNextExpectedSeqNo; // because we're finished with this packet now - - fHeadPacket = fHeadPacket->nextPacket(); - packet->nextPacket() = NULL; - - freePacket(packet); -} - -BufferedPacket* ReorderingPacketBuffer -::getNextCompletedPacket(Boolean& packetLossPreceded) { - if (fHeadPacket == NULL) return NULL; - - // Check whether the next packet we want is already at the head - // of the queue: - // ASSERT: fHeadPacket->rtpSeqNo() >= fNextExpectedSeqNo - if (fHeadPacket->rtpSeqNo() == fNextExpectedSeqNo) { - packetLossPreceded = False; - return fHeadPacket; - } - - // We're still waiting for our desired packet to arrive. However, if - // our time threshold has been exceeded, then forget it, and return - // the head packet instead: - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - unsigned uSecondsSinceReceived - = (timeNow.tv_sec - fHeadPacket->timeReceived().tv_sec)*1000000 - + (timeNow.tv_usec - fHeadPacket->timeReceived().tv_usec); - if (uSecondsSinceReceived > fThresholdTime) { - fNextExpectedSeqNo = fHeadPacket->rtpSeqNo(); - // we've given up on earlier packets now - packetLossPreceded = True; - return fHeadPacket; - } - - // Otherwise, keep waiting for our desired packet to arrive: - return NULL; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/OnDemandServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/OnDemandServerMediaSubsession.cpp deleted file mode 100644 index bcaf824dadc..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/OnDemandServerMediaSubsession.cpp +++ /dev/null @@ -1,487 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand. -// Implementation - -#include "OnDemandServerMediaSubsession.hh" -#include "RTCP.hh" -#include "BasicUDPSink.hh" -#include - -OnDemandServerMediaSubsession -::OnDemandServerMediaSubsession(UsageEnvironment& env, - Boolean reuseFirstSource) - : ServerMediaSubsession(env), - fReuseFirstSource(reuseFirstSource), fLastStreamToken(NULL), - fSDPLines(NULL) { - fDestinationsHashTable = HashTable::create(ONE_WORD_HASH_KEYS); - gethostname(fCNAME, sizeof fCNAME); - fCNAME[sizeof fCNAME-1] = '\0'; // just in case -} - -class Destinations { -public: - Destinations(struct in_addr const& destAddr, - Port const& rtpDestPort, - Port const& rtcpDestPort) - : isTCP(False), addr(destAddr), rtpPort(rtpDestPort), rtcpPort(rtcpDestPort) { - } - Destinations(int tcpSockNum, unsigned char rtpChanId, unsigned char rtcpChanId) - : isTCP(True), rtpPort(0) /*dummy*/, rtcpPort(0) /*dummy*/, - tcpSocketNum(tcpSockNum), rtpChannelId(rtpChanId), rtcpChannelId(rtcpChanId) { - } - -public: - Boolean isTCP; - struct in_addr addr; - Port rtpPort; - Port rtcpPort; - int tcpSocketNum; - unsigned char rtpChannelId, rtcpChannelId; -}; - -OnDemandServerMediaSubsession::~OnDemandServerMediaSubsession() { - delete[] fSDPLines; - - // Clean out the destinations hash table: - while (1) { - Destinations* destinations - = (Destinations*)(fDestinationsHashTable->RemoveNext()); - if (destinations == NULL) break; - delete destinations; - } - delete fDestinationsHashTable; -} - -char const* -OnDemandServerMediaSubsession::sdpLines() { - if (fSDPLines == NULL) { - // We need to construct a set of SDP lines that describe this - // subsession (as a unicast stream). To do so, we first create - // dummy (unused) source and "RTPSink" objects, - // whose parameters we use for the SDP lines: - unsigned estBitrate; // unused - FramedSource* inputSource = createNewStreamSource(0, estBitrate); - if (inputSource == NULL) return NULL; // file not found - - struct in_addr dummyAddr; - dummyAddr.s_addr = 0; - Groupsock dummyGroupsock(envir(), dummyAddr, 0, 0); - unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic - RTPSink* dummyRTPSink - = createNewRTPSink(&dummyGroupsock, rtpPayloadType, inputSource); - - setSDPLinesFromRTPSink(dummyRTPSink, inputSource); - Medium::close(dummyRTPSink); - Medium::close(inputSource); - } - - return fSDPLines; -} - -// A class that represents the state of an ongoing stream -class StreamState { -public: - StreamState(Port const& serverRTPPort, Port const& serverRTCPPort, - RTPSink* rtpSink, BasicUDPSink* udpSink, - float streamDuration, unsigned totalBW, char* CNAME, - FramedSource* mediaSource, - Groupsock* rtpGS, Groupsock* rtcpGS); - virtual ~StreamState(); - - void startPlaying(Destinations* destinations, - TaskFunc* rtcpRRHandler, void* rtcpRRHandlerClientData); - void pause(); - void endPlaying(Destinations* destinations); - void reclaim(); - - unsigned& referenceCount() { return fReferenceCount; } - - Port const& serverRTPPort() const { return fServerRTPPort; } - Port const& serverRTCPPort() const { return fServerRTCPPort; } - - RTPSink const* rtpSink() const { return fRTPSink; } - - float streamDuration() const { return fStreamDuration; } - - FramedSource* mediaSource() const { return fMediaSource; } - -private: - Boolean fAreCurrentlyPlaying; - unsigned fReferenceCount; - - Port fServerRTPPort, fServerRTCPPort; - - RTPSink* fRTPSink; - BasicUDPSink* fUDPSink; - - float fStreamDuration; - unsigned fTotalBW; char* fCNAME; RTCPInstance* fRTCPInstance; - - FramedSource* fMediaSource; - - Groupsock* fRTPgs; Groupsock* fRTCPgs; -}; - -void OnDemandServerMediaSubsession -::getStreamParameters(unsigned clientSessionId, - netAddressBits clientAddress, - Port const& clientRTPPort, - Port const& clientRTCPPort, - int tcpSocketNum, - unsigned char rtpChannelId, - unsigned char rtcpChannelId, - netAddressBits& destinationAddress, - u_int8_t& /*destinationTTL*/, - Boolean& isMulticast, - Port& serverRTPPort, - Port& serverRTCPPort, - void*& streamToken) { - if (destinationAddress == 0) destinationAddress = clientAddress; - struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress; - isMulticast = False; - - if (fLastStreamToken != NULL && fReuseFirstSource) { - // Special case: Rather than creating a new 'StreamState', - // we reuse the one that we've already created: - serverRTPPort = ((StreamState*)fLastStreamToken)->serverRTPPort(); - serverRTCPPort = ((StreamState*)fLastStreamToken)->serverRTCPPort(); - ++((StreamState*)fLastStreamToken)->referenceCount(); - streamToken = fLastStreamToken; - } else { - // Normal case: Create a new media source: - unsigned streamBitrate; - FramedSource* mediaSource - = createNewStreamSource(clientSessionId, streamBitrate); - - // Create a new 'groupsock' for the RTP destination, and make sure that - // its port number is even: - struct in_addr dummyAddr; dummyAddr.s_addr = 0; - Groupsock* rtpGroupsock; - Groupsock* rtpGroupsock_old = NULL; - portNumBits serverRTPPortNum = 0; - while (1) { - rtpGroupsock = new Groupsock(envir(), dummyAddr, 0, 255); - if (!getSourcePort(envir(), rtpGroupsock->socketNum(), serverRTPPort)) break; - serverRTPPortNum = ntohs(serverRTPPort.num()); - - // If the port number's even, we're done: - if ((serverRTPPortNum&1) == 0) break; - - // Try again (while keeping the old 'groupsock' around, so that we get - // a different socket number next time): - delete rtpGroupsock_old; - rtpGroupsock_old = rtpGroupsock; - } - delete rtpGroupsock_old; - - // Create a sink for this stream: - RTPSink* rtpSink; - BasicUDPSink* udpSink; - Groupsock* rtcpGroupsock; - if (clientRTCPPort.num() == 0) { - // We're streaming raw UDP (not RTP): - rtpSink = NULL; - udpSink = BasicUDPSink::createNew(envir(), rtpGroupsock); - rtcpGroupsock = NULL; - } else { - // Normal case: We're streaming RTP (over UDP or TCP): - unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic - rtpSink = createNewRTPSink(rtpGroupsock, rtpPayloadType, mediaSource); - udpSink = NULL; - - // Create a 'groupsock' for a 'RTCP instance' to be created later: - rtcpGroupsock = new Groupsock(envir(), dummyAddr, serverRTPPortNum+1, 255); - getSourcePort(envir(), rtcpGroupsock->socketNum(), serverRTCPPort); - } - - // Turn off the destinations for each groupsock. They'll get set later - // (unless TCP is used instead): - if (rtpGroupsock != NULL) rtpGroupsock->removeAllDestinations(); - if (rtcpGroupsock != NULL) rtcpGroupsock->removeAllDestinations(); - - // Set up the state of the stream. The stream will get started later: - streamToken = fLastStreamToken - = new StreamState(serverRTPPort, serverRTCPPort, rtpSink, udpSink, - duration(), streamBitrate, fCNAME, mediaSource, - rtpGroupsock, rtcpGroupsock); - } - - // Record these destinations as being for this client session id: - Destinations* destinations; - if (tcpSocketNum < 0) { // UDP - destinations = new Destinations(destinationAddr, clientRTPPort, clientRTCPPort); - } else { // TCP - destinations = new Destinations(tcpSocketNum, rtpChannelId, rtcpChannelId); - } - fDestinationsHashTable->Add((char const*)clientSessionId, destinations); -} - -void OnDemandServerMediaSubsession::startStream(unsigned clientSessionId, - void* streamToken, - TaskFunc* rtcpRRHandler, - void* rtcpRRHandlerClientData, - unsigned short& rtpSeqNum, - unsigned& rtpTimestamp) { - StreamState* streamState = (StreamState*)streamToken; - Destinations* destinations - = (Destinations*)(fDestinationsHashTable->Lookup((char const*)clientSessionId)); - if (streamState != NULL) { - streamState->startPlaying(destinations, - rtcpRRHandler, rtcpRRHandlerClientData); - if (streamState->rtpSink() != NULL) { - rtpSeqNum = streamState->rtpSink()->currentSeqNo(); - rtpTimestamp = streamState->rtpSink()->currentTimestamp(); - } - } -} - -void OnDemandServerMediaSubsession::pauseStream(unsigned /*clientSessionId*/, - void* streamToken) { - // Pausing isn't allowed if multiple clients are receiving data from - // the same source: - if (fReuseFirstSource) return; - - StreamState* streamState = (StreamState*)streamToken; - if (streamState != NULL) streamState->pause(); -} - -void OnDemandServerMediaSubsession::seekStream(unsigned /*clientSessionId*/, - void* streamToken, float seekNPT) { - // Seeking isn't allowed if multiple clients are receiving data from - // the same source: - if (fReuseFirstSource) return; - - StreamState* streamState = (StreamState*)streamToken; - if (streamState != NULL && streamState->mediaSource() != NULL) { - seekStreamSource(streamState->mediaSource(), seekNPT); - } -} - -void OnDemandServerMediaSubsession::setStreamScale(unsigned /*clientSessionId*/, - void* streamToken, float scale) { - // Changing the scale factor isn't allowed if multiple clients are receiving data - // from the same source: - if (fReuseFirstSource) return; - - StreamState* streamState = (StreamState*)streamToken; - if (streamState != NULL && streamState->mediaSource() != NULL) { - setStreamSourceScale(streamState->mediaSource(), scale); - } -} - -void OnDemandServerMediaSubsession::deleteStream(unsigned clientSessionId, - void*& streamToken) { - // Look up (and remove) the destinations for this client session: - Destinations* destinations - = (Destinations*)(fDestinationsHashTable->Lookup((char const*)clientSessionId)); - if (destinations != NULL) { - fDestinationsHashTable->Remove((char const*)clientSessionId); - } - - // Stop streaming to these destinations: - StreamState* streamState = (StreamState*)streamToken; - if (streamState != NULL) streamState->endPlaying(destinations); - - // Delete the "StreamState" structure if it's no longer being used: - if (streamState != NULL && streamState->referenceCount() > 0) { - --streamState->referenceCount(); - if (streamState->referenceCount() == 0) { - delete streamState; - if (fLastStreamToken == streamToken) fLastStreamToken = NULL; - streamToken = NULL; - } - } - - // Finally, delete the destinations themselves: - delete destinations; -} - -char const* OnDemandServerMediaSubsession -::getAuxSDPLine(RTPSink* rtpSink, FramedSource* /*inputSource*/) { - // Default implementation: - return rtpSink == NULL ? NULL : rtpSink->auxSDPLine(); -} - -void OnDemandServerMediaSubsession::seekStreamSource(FramedSource* /*inputSource*/, - float /*seekNPT*/) { - // Default implementation: Do nothing -} - -void OnDemandServerMediaSubsession -::setStreamSourceScale(FramedSource* /*inputSource*/, float /*scale*/) { - // Default implementation: Do nothing -} - -void OnDemandServerMediaSubsession -::setSDPLinesFromRTPSink(RTPSink* rtpSink, FramedSource* inputSource) { - if (rtpSink == NULL) return; - - char const* mediaType = rtpSink->sdpMediaType(); - unsigned char rtpPayloadType = rtpSink->rtpPayloadType(); - struct in_addr serverAddrForSDP; serverAddrForSDP.s_addr = fServerAddressForSDP; - char* const ipAddressStr = strDup(our_inet_ntoa(serverAddrForSDP)); - char* rtpmapLine = rtpSink->rtpmapLine(); - char const* rangeLine = rangeSDPLine(); - char const* auxSDPLine = getAuxSDPLine(rtpSink, inputSource); - if (auxSDPLine == NULL) auxSDPLine = ""; - - char const* const sdpFmt = - "m=%s %u RTP/AVP %d\r\n" - "c=IN IP4 %s\r\n" - "%s" - "%s" - "%s" - "a=control:%s\r\n"; - unsigned sdpFmtSize = strlen(sdpFmt) - + strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */ - + strlen(ipAddressStr) - + strlen(rtpmapLine) - + strlen(rangeLine) - + strlen(auxSDPLine) - + strlen(trackId()); - char* sdpLines = new char[sdpFmtSize]; - sprintf(sdpLines, sdpFmt, - mediaType, // m= - fPortNumForSDP, // m= - rtpPayloadType, // m= - ipAddressStr, // c= address - rtpmapLine, // a=rtpmap:... (if present) - rangeLine, // a=range:... (if present) - auxSDPLine, // optional extra SDP line - trackId()); // a=control: - delete[] (char*)rangeLine; delete[] rtpmapLine; delete[] ipAddressStr; - - fSDPLines = strDup(sdpLines); - delete[] sdpLines; -} - - -////////// StreamState implementation ////////// - -static void afterPlayingStreamState(void* clientData) { - StreamState* streamState = (StreamState*)clientData; - if (streamState->streamDuration() == 0.0) { - // When the input stream ends, tear it down. This will cause a RTCP "BYE" - // to be sent to each client, teling it that the stream has ended. - // (Because the stream didn't have a known duration, there was no other - // way for clients to know when the stream ended.) - streamState->reclaim(); - } - // Otherwise, keep the stream alive, in case a client wants to - // subsequently re-play the stream starting from somewhere other than the end. - // (This can be done only on streams that have a known duration.) -} - -StreamState::StreamState(Port const& serverRTPPort, Port const& serverRTCPPort, - RTPSink* rtpSink, BasicUDPSink* udpSink, - float streamDuration, unsigned totalBW, char* CNAME, - FramedSource* mediaSource, - Groupsock* rtpGS, Groupsock* rtcpGS) - : fAreCurrentlyPlaying(False), fReferenceCount(1), - fServerRTPPort(serverRTPPort), fServerRTCPPort(serverRTCPPort), - fRTPSink(rtpSink), fUDPSink(udpSink), fStreamDuration(streamDuration), - fTotalBW(totalBW), fCNAME(CNAME), fRTCPInstance(NULL) /* created later */, - fMediaSource(mediaSource), fRTPgs(rtpGS), fRTCPgs(rtcpGS) { -} - -StreamState::~StreamState() { - reclaim(); -} - -void StreamState -::startPlaying(Destinations* dests, - TaskFunc* rtcpRRHandler, void* rtcpRRHandlerClientData) { - if (dests == NULL) return; - if (!fAreCurrentlyPlaying && fMediaSource != NULL) { - if (fRTPSink != NULL) { - fRTPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this); - fAreCurrentlyPlaying = True; - } else if (fUDPSink != NULL) { - fUDPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this); - fAreCurrentlyPlaying = True; - } - } - - if (fRTCPInstance == NULL && fRTPSink != NULL) { - // Create (and start) a 'RTCP instance' for this RTP sink: - fRTCPInstance - = RTCPInstance::createNew(fRTPSink->envir(), fRTCPgs, - fTotalBW, (unsigned char*)fCNAME, - fRTPSink, NULL /* we're a server */); - // Note: This starts RTCP running automatically - } - if (fRTCPInstance != NULL) - fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr, dests->rtcpPort, - rtcpRRHandler, rtcpRRHandlerClientData); - - if (dests->isTCP) { - // Change RTP and RTCP to use the TCP socket instead of UDP: - if (fRTPSink != NULL) { - fRTPSink->addStreamSocket(dests->tcpSocketNum, dests->rtpChannelId); - } - if (fRTCPInstance != NULL) { - fRTCPInstance->addStreamSocket(dests->tcpSocketNum, dests->rtcpChannelId); - } - } else { - // Tell the RTP and RTCP 'groupsocks' about this destination - // (in case they don't already have it): - if (fRTPgs != NULL) fRTPgs->addDestination(dests->addr, dests->rtpPort); - if (fRTCPgs != NULL) fRTCPgs->addDestination(dests->addr, dests->rtcpPort); - } -} - -void StreamState::pause() { - if (fRTPSink != NULL) fRTPSink->stopPlaying(); - if (fUDPSink != NULL) fUDPSink->stopPlaying(); - fAreCurrentlyPlaying = False; -} - -void StreamState::endPlaying(Destinations* dests) { - if (dests->isTCP) { - if (fRTPSink != NULL) { - fRTPSink->removeStreamSocket(dests->tcpSocketNum, dests->rtpChannelId); - } - if (fRTCPInstance != NULL) { - fRTCPInstance->removeStreamSocket(dests->tcpSocketNum, dests->rtcpChannelId); - } - } else { - // Tell the RTP and RTCP 'groupsocks' to stop using these destinations: - if (fRTPgs != NULL) fRTPgs->removeDestination(dests->addr, dests->rtpPort); - if (fRTCPgs != NULL) fRTCPgs->removeDestination(dests->addr, dests->rtcpPort); - if (fRTCPInstance != NULL) { - fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr, dests->rtcpPort, - NULL, NULL); - } - } -} - -void StreamState::reclaim() { - // Delete allocated media objects - Medium::close(fRTCPInstance) /* will send a RTCP BYE */; fRTCPInstance = NULL; - Medium::close(fRTPSink); fRTPSink = NULL; - Medium::close(fUDPSink); fUDPSink = NULL; - - Medium::close(fMediaSource); fMediaSource = NULL; - - delete fRTPgs; fRTPgs = NULL; - delete fRTCPgs; fRTCPgs = NULL; - - fReferenceCount = 0; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/OutputFile.cpp b/mythtv/libs/libmythlivemedia/liveMedia/OutputFile.cpp deleted file mode 100644 index 3293efb9e73..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/OutputFile.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Common routines for opening/closing named output files -// Implementation - -#if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE) -#include -#include -#endif -#ifndef _WIN32_WCE -#include -#endif -#include - -#include "OutputFile.hh" - -FILE* OpenOutputFile(UsageEnvironment& env, char const* fileName) { - FILE* fid; - - // Check for special case 'file names': "stdout" and "stderr" - if (strcmp(fileName, "stdout") == 0) { - fid = stdout; -#if defined(__WIN32__) || defined(_WIN32) - _setmode(_fileno(stdout), _O_BINARY); // convert to binary mode -#endif - } else if (strcmp(fileName, "stderr") == 0) { - fid = stderr; -#if defined(__WIN32__) || defined(_WIN32) - _setmode(_fileno(stderr), _O_BINARY); // convert to binary mode -#endif - } else { - fid = fopen(fileName, "wb"); - } - - if (fid == NULL) { - env.setResultMsg("unable to open file \"", fileName, "\""); - } - - return fid; -} - -void CloseOutputFile(FILE* fid) { - // Don't close 'stdout' or 'stderr', in case we want to use it again later. - if (fid != NULL && fid != stdout && fid != stderr) fclose(fid); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/PassiveServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/PassiveServerMediaSubsession.cpp deleted file mode 100644 index c66c6f0ec06..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/PassiveServerMediaSubsession.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that represents an existing -// 'RTPSink', rather than one that creates new 'RTPSink's on demand. -// Implementation - -#include "PassiveServerMediaSubsession.hh" -#include - -////////// PassiveServerMediaSubsession ////////// - -PassiveServerMediaSubsession* -PassiveServerMediaSubsession::createNew(RTPSink& rtpSink, - RTCPInstance* rtcpInstance) { - return new PassiveServerMediaSubsession(rtpSink, rtcpInstance); -} - -PassiveServerMediaSubsession -::PassiveServerMediaSubsession(RTPSink& rtpSink, RTCPInstance* rtcpInstance) - : ServerMediaSubsession(rtpSink.envir()), - fRTPSink(rtpSink), fRTCPInstance(rtcpInstance), fSDPLines(NULL) { -} - -char const* -PassiveServerMediaSubsession::sdpLines() { - if (fSDPLines == NULL ) { - // Construct a set of SDP lines that describe this subsession: - // Use the components from "rtpSink": - Groupsock const& gs = fRTPSink.groupsockBeingUsed(); - struct in_addr const& ipAddress = gs.groupAddress(); - unsigned short portNum = ntohs(gs.port().num()); - unsigned char ttl = gs.ttl(); - unsigned char rtpPayloadType = fRTPSink.rtpPayloadType(); - char const* mediaType = fRTPSink.sdpMediaType(); - char* rtpmapLine = fRTPSink.rtpmapLine(); - char const* rangeLine = rangeSDPLine(); - char const* auxSDPLine = fRTPSink.auxSDPLine(); - if (auxSDPLine == NULL) auxSDPLine = ""; - - char* const ipAddressStr = strDup(our_inet_ntoa(ipAddress)); - - char const* const sdpFmt = - "m=%s %d RTP/AVP %d\r\n" - "c=IN IP4 %s/%d\r\n" - "%s" - "%s" - "%s" - "a=control:%s\r\n"; - unsigned sdpFmtSize = strlen(sdpFmt) - + strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */ - + strlen(ipAddressStr) + 3 /* max char len */ - + strlen(rtpmapLine) - + strlen(rangeLine) - + strlen(auxSDPLine) - + strlen(trackId()); - char* sdpLines = new char[sdpFmtSize]; - sprintf(sdpLines, sdpFmt, - mediaType, // m= - portNum, // m= - rtpPayloadType, // m= - ipAddressStr, // c= - ttl, // c= TTL - rtpmapLine, // a=rtpmap:... (if present) - rangeLine, // a=range:... (if present) - auxSDPLine, // optional extra SDP line - trackId()); // a=control: - delete[] ipAddressStr; delete[] (char*)rangeLine; delete[] rtpmapLine; - - fSDPLines = strDup(sdpLines); - delete[] sdpLines; - } - - return fSDPLines; -} - -void PassiveServerMediaSubsession -::getStreamParameters(unsigned /*clientSessionId*/, - netAddressBits /*clientAddress*/, - Port const& /*clientRTPPort*/, - Port const& /*clientRTCPPort*/, - int /*tcpSocketNum*/, - unsigned char /*rtpChannelId*/, - unsigned char /*rtcpChannelId*/, - netAddressBits& destinationAddress, - u_int8_t& destinationTTL, - Boolean& isMulticast, - Port& serverRTPPort, - Port& serverRTCPPort, - void*& streamToken) { - isMulticast = True; - Groupsock& gs = fRTPSink.groupsockBeingUsed(); - if (destinationTTL == 255) destinationTTL = gs.ttl(); - if (destinationAddress == 0) { // normal case - destinationAddress = gs.groupAddress().s_addr; - } else { // use the client-specified destination address instead: - struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress; - gs.changeDestinationParameters(destinationAddr, 0, destinationTTL); - if (fRTCPInstance != NULL) { - Groupsock* rtcpGS = fRTCPInstance->RTCPgs(); - rtcpGS->changeDestinationParameters(destinationAddr, 0, destinationTTL); - } - } - serverRTPPort = gs.port(); - if (fRTCPInstance != NULL) { - Groupsock* rtcpGS = fRTCPInstance->RTCPgs(); - serverRTCPPort = rtcpGS->port(); - } - streamToken = NULL; // not used -} - -void PassiveServerMediaSubsession::startStream(unsigned /*clientSessionId*/, - void* /*streamToken*/, - TaskFunc* /*rtcpRRHandler*/, - void* /*rtcpRRHandlerClientData*/, - unsigned short& rtpSeqNum, - unsigned& rtpTimestamp) { - // Note: We don't set a RTCP RR handler, because (i) we're called potentially - // many times on the same "RTCPInstance", and (ii) the "RTCPInstance" remains - // in existence after "deleteStream()" is called. - rtpSeqNum = fRTPSink.currentSeqNo(); - rtpTimestamp = fRTPSink.currentTimestamp(); -} - -PassiveServerMediaSubsession::~PassiveServerMediaSubsession() { - delete[] fSDPLines; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/PrioritizedRTPStreamSelector.cpp b/mythtv/libs/libmythlivemedia/liveMedia/PrioritizedRTPStreamSelector.cpp deleted file mode 100644 index f0770f643d3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/PrioritizedRTPStreamSelector.cpp +++ /dev/null @@ -1,474 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Select from multiple, prioritized RTP streams, based on RTP sequence -// number, producing a single output stream -// Implementation - -#include "PrioritizedRTPStreamSelector.hh" -#include "GroupsockHelper.hh" -#include -#include - -////////// PrioritizedInputStreamDescriptor ////////// - -// A data structure used to describe each input stream: -class PrioritizedInputStreamDescriptor { -public: - PrioritizedInputStreamDescriptor(PrioritizedRTPStreamSelector* - ourSelector, - PrioritizedInputStreamDescriptor* next, - unsigned priority, - RTPSource* inputStream, - RTCPInstance* inputStreamRTCP); - virtual ~PrioritizedInputStreamDescriptor(); - - PrioritizedInputStreamDescriptor*& next() { return fNext; } - unsigned priority() const { return fPriority; } - RTPSource* rtpStream() const { return fRTPStream; } - unsigned char*& buffer() { return fBuffer; } - unsigned bufferSize() const { return fBufferSize; } - - void afterGettingFrame1(unsigned frameSize); - void onSourceClosure1(); - -private: - PrioritizedRTPStreamSelector* fOurSelector; - PrioritizedInputStreamDescriptor* fNext; - unsigned fPriority; - RTPSource* fRTPStream; - RTCPInstance* fRTCPStream; - unsigned char* fBuffer; // where to put the next frame from this stream - static unsigned const fBufferSize; - unsigned fBufferBytesUsed; -}; - -static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); -static void onSourceClosure(void* clientData); - - -////////// PacketWarehouse ////////// - -class WarehousedPacketDescriptor; // forward - -class PacketWarehouse { -public: - PacketWarehouse(unsigned seqNumStagger); - virtual ~PacketWarehouse(); - - Boolean isFull(); - void addNewFrame(unsigned priority, unsigned short rtpSeqNo, - unsigned char* buffer, unsigned frameSize); - unsigned char* dequeueFrame(unsigned& resultFrameSize, - unsigned& uSecondsToDefer); - - Boolean fLastActionWasIncoming; -private: - WarehousedPacketDescriptor* fPacketDescriptors; - Boolean fHaveReceivedFrames; - unsigned short fMinSeqNumStored, fMaxSeqNumStored; - unsigned const fMinSpanForDelivery, fMaxSpanForDelivery, fNumDescriptors; - struct timeval fLastArrivalTime; unsigned short fLastRTPSeqNo; - unsigned fInterArrivalAveGap; // in microseconds -}; - -////////// PrioritizedRTPStreamSelector implementation ////////// - -PrioritizedRTPStreamSelector -::PrioritizedRTPStreamSelector(UsageEnvironment& env, - unsigned seqNumStagger) - : FramedSource(env), - fNextInputStreamPriority(0), fInputStreams(NULL), - fAmCurrentlyReading(False), fNeedAFrame(False) { - fWarehouse = new PacketWarehouse(seqNumStagger); -} - -PrioritizedRTPStreamSelector::~PrioritizedRTPStreamSelector() { - delete fWarehouse; - - while (fInputStreams != NULL) { - PrioritizedInputStreamDescriptor* inputStream - = fInputStreams; - fInputStreams = inputStream->next(); - delete inputStream; - } -} - -PrioritizedRTPStreamSelector* PrioritizedRTPStreamSelector -::createNew(UsageEnvironment& env, unsigned seqNumStagger) { - return new PrioritizedRTPStreamSelector(env, seqNumStagger); -} - -unsigned PrioritizedRTPStreamSelector -::addInputRTPStream(RTPSource* inputStream, - RTCPInstance* inputStreamRTCP) { - fInputStreams - = new PrioritizedInputStreamDescriptor(this, fInputStreams, - fNextInputStreamPriority, - inputStream, inputStreamRTCP); - return fNextInputStreamPriority++; -} - -void PrioritizedRTPStreamSelector::removeInputRTPStream(unsigned priority) { - for (PrioritizedInputStreamDescriptor*& inputStream - = fInputStreams; - inputStream != NULL; inputStream = inputStream->next()) { - if (inputStream->priority() == priority) { - PrioritizedInputStreamDescriptor* toDelete - = inputStream; - inputStream->next() = toDelete->next(); - delete toDelete; - break; - } - } -} - -Boolean PrioritizedRTPStreamSelector -::lookupByName(UsageEnvironment& env, - char const* sourceName, - PrioritizedRTPStreamSelector*& resultSelector) { - resultSelector = NULL; // unless we succeed - - FramedSource* source; - if (!FramedSource::lookupByName(env, sourceName, source)) return False; - - if (!source->isPrioritizedRTPStreamSelector()) { - env.setResultMsg(sourceName, " is not a Prioritized RTP Stream Selector"); - return False; - } - - resultSelector = (PrioritizedRTPStreamSelector*)source; - return True; -} - -Boolean PrioritizedRTPStreamSelector -::isPrioritizedRTPStreamSelector() const { - return True; -} - -void PrioritizedRTPStreamSelector::doGetNextFrame() { - // Begin the process of reading frames from our sources into the - // frame 'warehouse' (unless this is already ongoing): - startReadingProcess(); - - // (Try to) give ourselves a frame from our warehouse: - unsigned uSecondsToDefer; - if (deliverFrameToClient(uSecondsToDefer)) { - fNeedAFrame = False; - - // Complete the delivery. If we were told to delay before doing - // this, then schedule this as a delayed task: - if (uSecondsToDefer > 0) { - nextTask() - = envir().taskScheduler().scheduleDelayedTask((int)uSecondsToDefer, - completeDelivery, - this); - } else { - completeDelivery(this); - } - } else { - fNeedAFrame = True; - } -} - -void PrioritizedRTPStreamSelector::startReadingProcess() { - if (fAmCurrentlyReading) return; // already ongoing - if (fWarehouse->isFull()) return; // no room now for any more - - // Run through each input stream, requesting a new frame from it - // (unless a previous read on this frame is still in progress). - // When a frame arrives on one of the input streams, it will get - // stored in our 'warehouse', for later delivery to us. - for (PrioritizedInputStreamDescriptor* inputStream - = fInputStreams; - inputStream != NULL; inputStream = inputStream->next()) { - RTPSource* rtpStream = inputStream->rtpStream(); - if (!rtpStream->isCurrentlyAwaitingData()) { - // Read a frame into this stream's descriptor's buffer: - fAmCurrentlyReading = True; - rtpStream->getNextFrame(inputStream->buffer(), - inputStream->bufferSize(), - afterGettingFrame, inputStream, - onSourceClosure, inputStream); - } - } -} - -void PrioritizedRTPStreamSelector -::handleNewIncomingFrame(unsigned priority, unsigned short rtpSeqNo, - unsigned char* buffer, unsigned frameSize) { - // Begin by adding this new frame to the warehouse: - fWarehouse->addNewFrame(priority, rtpSeqNo, buffer, frameSize); - fWarehouse->fLastActionWasIncoming = True; - - // Try again to deliver a frame for our client (if he still wants one): - if (fNeedAFrame) { - doGetNextFrame(); - } - - // Continue the reading process: - fAmCurrentlyReading = False; - startReadingProcess(); -} - -Boolean PrioritizedRTPStreamSelector -::deliverFrameToClient(unsigned& uSecondsToDefer) { - unsigned char* buffer - = fWarehouse->dequeueFrame(fFrameSize, uSecondsToDefer); - - if (buffer != NULL) { - // A frame was available - if (fFrameSize > fMaxSize) { - fNumTruncatedBytes = fFrameSize - fMaxSize; - fFrameSize = fMaxSize; - } - memmove(fTo, buffer, fFrameSize); - - delete[] buffer; - fWarehouse->fLastActionWasIncoming = False; - return True; - } - - // No frame was available. - return False; -} - - -void PrioritizedRTPStreamSelector::completeDelivery(void* clientData) { - PrioritizedRTPStreamSelector* selector - = (PrioritizedRTPStreamSelector*)clientData; - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking infinite recursion. - FramedSource::afterGetting(selector); -} - - -//////// PrioritizedInputStreamDescriptor implementation //////// - -unsigned const PrioritizedInputStreamDescriptor::fBufferSize = 4000; - -PrioritizedInputStreamDescriptor -::PrioritizedInputStreamDescriptor(PrioritizedRTPStreamSelector* - ourSelector, - PrioritizedInputStreamDescriptor* next, - unsigned priority, - RTPSource* inputStream, - RTCPInstance* inputStreamRTCP) - : fOurSelector(ourSelector), fNext(next), fPriority(priority), - fRTPStream(inputStream), fRTCPStream(inputStreamRTCP) { - fBuffer = new unsigned char[fBufferSize]; - fBufferBytesUsed = 0; -} - -PrioritizedInputStreamDescriptor::~PrioritizedInputStreamDescriptor() { - delete[] fBuffer; -} - -static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval /*presentationTime*/, - unsigned /*durationInMicroseconds*/) { - PrioritizedInputStreamDescriptor* inputStream - = (PrioritizedInputStreamDescriptor*)clientData; - inputStream->afterGettingFrame1(frameSize); -} - -void PrioritizedInputStreamDescriptor -::afterGettingFrame1(unsigned frameSize) { - unsigned short rtpSeqNo = rtpStream()->curPacketRTPSeqNum(); - // Deliver this frame to our selector: - fOurSelector->handleNewIncomingFrame(fPriority, rtpSeqNo, - fBuffer, frameSize); -} - -static void onSourceClosure(void* clientData) { - PrioritizedInputStreamDescriptor* inputStream - = (PrioritizedInputStreamDescriptor*)clientData; - inputStream->onSourceClosure1(); -} - -void PrioritizedInputStreamDescriptor::onSourceClosure1() { - fOurSelector->removeInputRTPStream(fPriority); -} - - -////////// WarehousedPacketDescriptor ////////// - -class WarehousedPacketDescriptor { -public: - WarehousedPacketDescriptor() : buffer(NULL) {} - // Don't define a destructor; for some reason it causes a crash ##### - - unsigned priority; - unsigned frameSize; - unsigned char* buffer; -}; - - -////////// PacketWarehouse implementation - -PacketWarehouse::PacketWarehouse(unsigned seqNumStagger) - : fLastActionWasIncoming(False), - fHaveReceivedFrames(False), fMinSeqNumStored(0), fMaxSeqNumStored(0), - fMinSpanForDelivery((unsigned)(1.5*seqNumStagger)), - fMaxSpanForDelivery(3*seqNumStagger), - fNumDescriptors(4*seqNumStagger), - fInterArrivalAveGap(0) { - fPacketDescriptors = new WarehousedPacketDescriptor[fNumDescriptors]; - if (fPacketDescriptors == NULL) { -#ifdef DEBUG - fprintf(stderr, "PacketWarehouse failed to allocate %d descriptors; seqNumStagger too large!\n", fNumDescriptors); -#endif - exit(1); - } - - // Initially, set "fLastArrivalTime" to the current time: - gettimeofday(&fLastArrivalTime, NULL); -} - -PacketWarehouse::~PacketWarehouse() { - // Delete each descriptor's buffer (if any), then delete the descriptors: - for (unsigned i = 0; i < fNumDescriptors; ++i) { - delete[] fPacketDescriptors[i].buffer; - } - delete[] fPacketDescriptors; -} - -Boolean PacketWarehouse::isFull() { - int currentSpan = fMaxSeqNumStored - fMinSeqNumStored; - if (currentSpan < 0) currentSpan += 65536; - - return (unsigned)currentSpan >= fNumDescriptors; -} - -void PacketWarehouse::addNewFrame(unsigned priority, - unsigned short rtpSeqNo, - unsigned char* buffer, - unsigned frameSize) { - if (!fHaveReceivedFrames) { - // This is our first frame; set up initial parameters: - // (But note hack: We want the first frame to have priority 0, so that - // receivers' decoders are happy, by seeing the 'best' data initially) - if (priority != 0) return; - - fMinSeqNumStored = fMaxSeqNumStored = rtpSeqNo; - fHaveReceivedFrames = True; - } else { - // Update our record of the maximum sequence number stored - if (seqNumLT(fMaxSeqNumStored, rtpSeqNo)) { - fMaxSeqNumStored = rtpSeqNo; - } else if (seqNumLT(rtpSeqNo, fMinSeqNumStored)) { - return; // ignore this packet; it's too old for us - } - } - - if (isFull()) { - // We've gotten way ahead of ourselves, probably due to a very large - // set of consecutive lost packets. To recover, reset our min/max - // sequence numbers (effectively emptying the warehouse). Hopefully, - // this should be an unusual occurrence: - fMinSeqNumStored = fMaxSeqNumStored = rtpSeqNo; - } - - // Check whether a frame with this sequence number has already been seen - WarehousedPacketDescriptor& desc - = fPacketDescriptors[rtpSeqNo%fNumDescriptors]; - if (desc.buffer != NULL) { - // We already have a frame. If it's priority is higher than that of - // this new frame, then we continue to use it: - if (desc.priority < priority) return; // lower than existing priority - - // Otherwise, use the new frame instead, so get rid of the existing one: - delete[] desc.buffer; - } - - // Record this new frame: - desc.buffer = new unsigned char[frameSize]; - if (desc.buffer == NULL) { -#ifdef DEBUG - fprintf(stderr, "PacketWarehouse::addNewFrame failed to allocate %d-byte buffer!\n", frameSize); -#endif - exit(1); - } - memmove(desc.buffer, buffer, frameSize); - desc.frameSize = frameSize; - desc.priority = priority; - - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - - if (rtpSeqNo == (fLastRTPSeqNo+1)%65536) { - // We've received consecutive packets, so update the estimate of - // the average inter-arrival gap: - unsigned lastGap // in microseconds - = (timeNow.tv_sec - fLastArrivalTime.tv_sec)*1000000 - + (timeNow.tv_usec - fLastArrivalTime.tv_usec); - - fInterArrivalAveGap = (9*fInterArrivalAveGap + lastGap)/10; // weighted - } - fLastArrivalTime = timeNow; - fLastRTPSeqNo = rtpSeqNo; -} - -unsigned char* PacketWarehouse::dequeueFrame(unsigned& resultFrameSize, - unsigned& uSecondsToDefer) { - uSecondsToDefer = 0; // by default - - // Don't return anything if we don't yet have enough packets to - // cover our desired sequence number span - int currentSpan = fMaxSeqNumStored - fMinSeqNumStored; - if (currentSpan < 0) currentSpan += 65536; - if (currentSpan < (int)fMinSpanForDelivery) { - return NULL; // we're not ready - } - - // Now, if our stored packet range is less than the desired maximum, - // return a frame, but delay this unless no incoming frames have - // arrived since the last time a frame was delivered to our client. - // This causes the buffer to empty only if the flow of incoming - // frames stops. - if (currentSpan < (int)fMaxSpanForDelivery) { - if (fLastActionWasIncoming) { - uSecondsToDefer = (unsigned)(1.5*fInterArrivalAveGap); - } - } - - // Now, return a frame: - unsigned char* resultBuffer = NULL; - do { - if (currentSpan < (int)fMinSpanForDelivery) break; - - WarehousedPacketDescriptor& desc - = fPacketDescriptors[fMinSeqNumStored%fNumDescriptors]; - resultBuffer = desc.buffer; - resultFrameSize = desc.frameSize; - - desc.buffer = NULL; -#ifdef DEBUG - if (resultBuffer == NULL) fprintf(stderr, "No packet for seq num %d - skipping\n", fMinSeqNumStored); //##### - else if (desc.priority == 2) fprintf(stderr, "Using priority %d frame for seq num %d\n", desc.priority, fMinSeqNumStored);//##### -#endif - fMinSeqNumStored = (fMinSeqNumStored+1)%65536; - --currentSpan; - } while (resultBuffer == NULL); // skip over missing packets - - return resultBuffer; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/QCELPAudioRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/QCELPAudioRTPSource.cpp deleted file mode 100644 index f9d24d30e57..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/QCELPAudioRTPSource.cpp +++ /dev/null @@ -1,498 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Qualcomm "PureVoice" (aka. "QCELP") Audio RTP Sources -// Implementation - -#include "QCELPAudioRTPSource.hh" -#include "MultiFramedRTPSource.hh" -#include "FramedFilter.hh" -#include -#include - -// This source is implemented internally by two separate sources: -// (i) a RTP source for the raw (interleaved) QCELP frames, and -// (ii) a deinterleaving filter that reads from this. -// Define these two new classes here: - -class RawQCELPRTPSource: public MultiFramedRTPSource { -public: - static RawQCELPRTPSource* createNew(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - - unsigned char interleaveL() const { return fInterleaveL; } - unsigned char interleaveN() const { return fInterleaveN; } - unsigned char& frameIndex() { return fFrameIndex; } // index within pkt - -private: - RawQCELPRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - - virtual ~RawQCELPRTPSource(); - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; - - virtual Boolean hasBeenSynchronizedUsingRTCP(); - -private: - unsigned char fInterleaveL, fInterleaveN, fFrameIndex; - unsigned fNumSuccessiveSyncedPackets; -}; - -class QCELPDeinterleaver: public FramedFilter { -public: - static QCELPDeinterleaver* createNew(UsageEnvironment& env, - RawQCELPRTPSource* inputSource); - -private: - QCELPDeinterleaver(UsageEnvironment& env, - RawQCELPRTPSource* inputSource); - // called only by "createNew()" - - virtual ~QCELPDeinterleaver(); - - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, struct timeval presentationTime); - -private: - // Redefined virtual functions: - void doGetNextFrame(); - -private: - class QCELPDeinterleavingBuffer* fDeinterleavingBuffer; - Boolean fNeedAFrame; -}; - - -////////// QCELPAudioRTPSource implementation ////////// - -FramedSource* -QCELPAudioRTPSource::createNew(UsageEnvironment& env, - Groupsock* RTPgs, - RTPSource*& resultRTPSource, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - RawQCELPRTPSource* rawRTPSource; - resultRTPSource = rawRTPSource - = RawQCELPRTPSource::createNew(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); - if (resultRTPSource == NULL) return NULL; - - QCELPDeinterleaver* deinterleaver - = QCELPDeinterleaver::createNew(env, rawRTPSource); - if (deinterleaver == NULL) { - Medium::close(resultRTPSource); - resultRTPSource = NULL; - } - - return deinterleaver; -} - - -////////// QCELPBufferedPacket and QCELPBufferedPacketFactory ////////// - -// A subclass of BufferedPacket, used to separate out QCELP frames. - -class QCELPBufferedPacket: public BufferedPacket { -public: - QCELPBufferedPacket(RawQCELPRTPSource& ourSource); - virtual ~QCELPBufferedPacket(); - -private: // redefined virtual functions - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); -private: - RawQCELPRTPSource& fOurSource; -}; - -class QCELPBufferedPacketFactory: public BufferedPacketFactory { -private: // redefined virtual functions - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - - -///////// RawQCELPRTPSource implementation //////// - -RawQCELPRTPSource* -RawQCELPRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) { - return new RawQCELPRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency); -} - -RawQCELPRTPSource::RawQCELPRTPSource(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency) - : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, - new QCELPBufferedPacketFactory), - fInterleaveL(0), fInterleaveN(0), fFrameIndex(0), - fNumSuccessiveSyncedPackets(0) { -} - -RawQCELPRTPSource::~RawQCELPRTPSource() { -} - -Boolean RawQCELPRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - unsigned char* headerStart = packet->data(); - unsigned packetSize = packet->dataSize(); - - // First, check whether this packet's RTP timestamp is synchronized: - if (RTPSource::hasBeenSynchronizedUsingRTCP()) { - ++fNumSuccessiveSyncedPackets; - } else { - fNumSuccessiveSyncedPackets = 0; - } - - // There's a 1-byte header indicating the interleave parameters - if (packetSize < 1) return False; - - // Get the interleaving parameters from the 1-byte header, - // and check them for validity: - unsigned char const firstByte = headerStart[0]; - unsigned char const interleaveL = (firstByte&0x38)>>3; - unsigned char const interleaveN = firstByte&0x07; -#ifdef DEBUG - fprintf(stderr, "packetSize: %d, interleaveL: %d, interleaveN: %d\n", packetSize, interleaveL, interleaveN); -#endif - if (interleaveL > 5 || interleaveN > interleaveL) return False; //invalid - - fInterleaveL = interleaveL; - fInterleaveN = interleaveN; - fFrameIndex = 0; // initially - - resultSpecialHeaderSize = 1; - return True; -} - -char const* RawQCELPRTPSource::MIMEtype() const { - return "audio/QCELP"; -} - -Boolean RawQCELPRTPSource::hasBeenSynchronizedUsingRTCP() { - // Don't report ourselves as being synchronized until we've received - // at least a complete interleave cycle of synchronized packets. - // This ensures that the receiver is currently getting a frame from - // a packet that was synchronized. - if (fNumSuccessiveSyncedPackets > (unsigned)(fInterleaveL+1)) { - fNumSuccessiveSyncedPackets = fInterleaveL+2; // prevents overflow - return True; - } - return False; -} - - -///// QCELPBufferedPacket and QCELPBufferedPacketFactory implementation - -QCELPBufferedPacket::QCELPBufferedPacket(RawQCELPRTPSource& ourSource) - : fOurSource(ourSource) { -} - -QCELPBufferedPacket::~QCELPBufferedPacket() { -} - -unsigned QCELPBufferedPacket:: - nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { - // The size of the QCELP frame is determined by the first byte: - if (dataSize == 0) return 0; // sanity check - unsigned char const firstByte = framePtr[0]; - - unsigned frameSize; - switch (firstByte) { - case 0: { frameSize = 1; break; } - case 1: { frameSize = 4; break; } - case 2: { frameSize = 8; break; } - case 3: { frameSize = 17; break; } - case 4: { frameSize = 35; break; } - default: { frameSize = 0; break; } - } - -#ifdef DEBUG - fprintf(stderr, "QCELPBufferedPacket::nextEnclosedFrameSize(): frameSize: %d, dataSize: %d\n", frameSize, dataSize); -#endif - if (dataSize < frameSize) return 0; - - ++fOurSource.frameIndex(); - return frameSize; -} - -BufferedPacket* QCELPBufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* ourSource) { - return new QCELPBufferedPacket((RawQCELPRTPSource&)(*ourSource)); -} - -///////// QCELPDeinterleavingBuffer ///////// -// (used to implement QCELPDeinterleaver) - -#define QCELP_MAX_FRAME_SIZE 35 -#define QCELP_MAX_INTERLEAVE_L 5 -#define QCELP_MAX_FRAMES_PER_PACKET 10 -#define QCELP_MAX_INTERLEAVE_GROUP_SIZE \ - ((QCELP_MAX_INTERLEAVE_L+1)*QCELP_MAX_FRAMES_PER_PACKET) - -class QCELPDeinterleavingBuffer { -public: - QCELPDeinterleavingBuffer(); - virtual ~QCELPDeinterleavingBuffer(); - - void deliverIncomingFrame(unsigned frameSize, - unsigned char interleaveL, - unsigned char interleaveN, - unsigned char frameIndex, - unsigned short packetSeqNum, - struct timeval presentationTime); - Boolean retrieveFrame(unsigned char* to, unsigned maxSize, - unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes, - struct timeval& resultPresentationTime); - - unsigned char* inputBuffer() { return fInputBuffer; } - unsigned inputBufferSize() const { return QCELP_MAX_FRAME_SIZE; } - -private: - class FrameDescriptor { - public: - FrameDescriptor(); - virtual ~FrameDescriptor(); - - unsigned frameSize; - unsigned char* frameData; - struct timeval presentationTime; - }; - - // Use two banks of descriptors - one for incoming, one for outgoing - FrameDescriptor fFrames[QCELP_MAX_INTERLEAVE_GROUP_SIZE][2]; - unsigned char fIncomingBankId; // toggles between 0 and 1 - unsigned char fIncomingBinMax; // in the incoming bank - unsigned char fOutgoingBinMax; // in the outgoing bank - unsigned char fNextOutgoingBin; - Boolean fHaveSeenPackets; - u_int16_t fLastPacketSeqNumForGroup; - unsigned char* fInputBuffer; - struct timeval fLastRetrievedPresentationTime; -}; - - -////////// QCELPDeinterleaver implementation ///////// - -QCELPDeinterleaver* -QCELPDeinterleaver::createNew(UsageEnvironment& env, - RawQCELPRTPSource* inputSource) { - return new QCELPDeinterleaver(env, inputSource); -} - -QCELPDeinterleaver::QCELPDeinterleaver(UsageEnvironment& env, - RawQCELPRTPSource* inputSource) - : FramedFilter(env, inputSource), - fNeedAFrame(False) { - fDeinterleavingBuffer = new QCELPDeinterleavingBuffer(); -} - -QCELPDeinterleaver::~QCELPDeinterleaver() { - delete fDeinterleavingBuffer; -} - -static unsigned const uSecsPerFrame = 20000; // 20 ms - -void QCELPDeinterleaver::doGetNextFrame() { - // First, try getting a frame from the deinterleaving buffer: - if (fDeinterleavingBuffer->retrieveFrame(fTo, fMaxSize, - fFrameSize, fNumTruncatedBytes, - fPresentationTime)) { - // Success! - fNeedAFrame = False; - - fDurationInMicroseconds = uSecsPerFrame; - - // Call our own 'after getting' function. Because we're not a 'leaf' - // source, we can call this directly, without risking - // infinite recursion - afterGetting(this); - return; - } - - // No luck, so ask our source for help: - fNeedAFrame = True; - if (!fInputSource->isCurrentlyAwaitingData()) { - fInputSource->getNextFrame(fDeinterleavingBuffer->inputBuffer(), - fDeinterleavingBuffer->inputBufferSize(), - afterGettingFrame, this, - FramedSource::handleClosure, this); - } -} - -void QCELPDeinterleaver -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - QCELPDeinterleaver* deinterleaver = (QCELPDeinterleaver*)clientData; - deinterleaver->afterGettingFrame1(frameSize, presentationTime); -} - -void QCELPDeinterleaver -::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime) { - RawQCELPRTPSource* source = (RawQCELPRTPSource*)fInputSource; - - // First, put the frame into our deinterleaving buffer: - fDeinterleavingBuffer - ->deliverIncomingFrame(frameSize, source->interleaveL(), - source->interleaveN(), source->frameIndex(), - source->curPacketRTPSeqNum(), - presentationTime); - - // Then, try delivering a frame to the client (if he wants one): - if (fNeedAFrame) doGetNextFrame(); -} - - -////////// QCELPDeinterleavingBuffer implementation ///////// - -QCELPDeinterleavingBuffer::QCELPDeinterleavingBuffer() - : fIncomingBankId(0), fIncomingBinMax(0), - fOutgoingBinMax(0), fNextOutgoingBin(0), - fHaveSeenPackets(False) { - fInputBuffer = new unsigned char[QCELP_MAX_FRAME_SIZE]; -} - -QCELPDeinterleavingBuffer::~QCELPDeinterleavingBuffer() { - delete[] fInputBuffer; -} - -void QCELPDeinterleavingBuffer -::deliverIncomingFrame(unsigned frameSize, - unsigned char interleaveL, - unsigned char interleaveN, - unsigned char frameIndex, - unsigned short packetSeqNum, - struct timeval presentationTime) { - // First perform a sanity check on the parameters: - // (This is overkill, as the source should have already done this.) - if (frameSize > QCELP_MAX_FRAME_SIZE - || interleaveL > QCELP_MAX_INTERLEAVE_L || interleaveN > interleaveL - || frameIndex == 0 || frameIndex > QCELP_MAX_FRAMES_PER_PACKET) { -#ifdef DEBUG - fprintf(stderr, "QCELPDeinterleavingBuffer::deliverIncomingFrame() param sanity check failed (%d,%d,%d,%d)\n", frameSize, interleaveL, interleaveN, frameIndex); -#endif - exit(1); - } - - // The input "presentationTime" was that of the first frame in this - // packet. Update it for the current frame: - unsigned uSecIncrement = (frameIndex-1)*(interleaveL+1)*uSecsPerFrame; - presentationTime.tv_usec += uSecIncrement; - presentationTime.tv_sec += presentationTime.tv_usec/1000000; - presentationTime.tv_usec = presentationTime.tv_usec%1000000; - - // Next, check whether this packet is part of a new interleave group - if (!fHaveSeenPackets - || seqNumLT(fLastPacketSeqNumForGroup, packetSeqNum)) { - // We've moved to a new interleave group - fHaveSeenPackets = True; - fLastPacketSeqNumForGroup = packetSeqNum + interleaveL - interleaveN; - - // Switch the incoming and outgoing banks: - fIncomingBankId ^= 1; - unsigned char tmp = fIncomingBinMax; - fIncomingBinMax = fOutgoingBinMax; - fOutgoingBinMax = tmp; - fNextOutgoingBin = 0; - } - - // Now move the incoming frame into the appropriate bin: - unsigned const binNumber - = interleaveN + (frameIndex-1)*(interleaveL+1); - FrameDescriptor& inBin = fFrames[binNumber][fIncomingBankId]; - unsigned char* curBuffer = inBin.frameData; - inBin.frameData = fInputBuffer; - inBin.frameSize = frameSize; - inBin.presentationTime = presentationTime; - - if (curBuffer == NULL) curBuffer = new unsigned char[QCELP_MAX_FRAME_SIZE]; - fInputBuffer = curBuffer; - - if (binNumber >= fIncomingBinMax) { - fIncomingBinMax = binNumber + 1; - } -} - -Boolean QCELPDeinterleavingBuffer -::retrieveFrame(unsigned char* to, unsigned maxSize, - unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes, - struct timeval& resultPresentationTime) { - if (fNextOutgoingBin >= fOutgoingBinMax) return False; // none left - - FrameDescriptor& outBin = fFrames[fNextOutgoingBin][fIncomingBankId^1]; - unsigned char* fromPtr; - unsigned char fromSize = outBin.frameSize; - outBin.frameSize = 0; // for the next time this bin is used - - // Check whether this frame is missing; if so, return an 'erasure' frame: - unsigned char erasure = 14; - if (fromSize == 0) { - fromPtr = &erasure; - fromSize = 1; - - // Compute this erasure frame's presentation time via extrapolation: - resultPresentationTime = fLastRetrievedPresentationTime; - resultPresentationTime.tv_usec += uSecsPerFrame; - if (resultPresentationTime.tv_usec >= 1000000) { - ++resultPresentationTime.tv_sec; - resultPresentationTime.tv_usec -= 1000000; - } - } else { - // Normal case - a frame exists: - fromPtr = outBin.frameData; - resultPresentationTime = outBin.presentationTime; - } - - fLastRetrievedPresentationTime = resultPresentationTime; - - if (fromSize > maxSize) { - resultNumTruncatedBytes = fromSize - maxSize; - resultFrameSize = maxSize; - } else { - resultNumTruncatedBytes = 0; - resultFrameSize = fromSize; - } - memmove(to, fromPtr, resultFrameSize); - - ++fNextOutgoingBin; - return True; -} - -QCELPDeinterleavingBuffer::FrameDescriptor::FrameDescriptor() - : frameSize(0), frameData(NULL) { -} - -QCELPDeinterleavingBuffer::FrameDescriptor::~FrameDescriptor() { - delete[] frameData; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/QuickTimeFileSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/QuickTimeFileSink.cpp deleted file mode 100644 index 14d2c0da1f4..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/QuickTimeFileSink.cpp +++ /dev/null @@ -1,2097 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A sink that generates a QuickTime file from a composite media session -// Implementation - -#include "QuickTimeFileSink.hh" -#include "QuickTimeGenericRTPSource.hh" -#include "GroupsockHelper.hh" -#include "OutputFile.hh" -#include "H263plusVideoRTPSource.hh" // for the special header -#include "MPEG4GenericRTPSource.hh" //for "samplingFrequencyFromAudioSpecificConfig()" -#include "MPEG4LATMAudioRTPSource.hh" // for "parseGeneralConfigStr()" - -#include - -#define fourChar(x,y,z,w) ( ((x)<<24)|((y)<<16)|((z)<<8)|(w) ) - -////////// SubsessionIOState, ChunkDescriptor /////////// -// A structure used to represent the I/O state of each input 'subsession': - -class ChunkDescriptor { -public: - ChunkDescriptor(unsigned offsetInFile, unsigned size, - unsigned frameSize, unsigned frameDuration, - struct timeval presentationTime); - virtual ~ChunkDescriptor(); - - ChunkDescriptor* extendChunk(unsigned newOffsetInFile, unsigned newSize, - unsigned newFrameSize, - unsigned newFrameDuration, - struct timeval newPresentationTime); - // this may end up allocating a new chunk instead -public: - ChunkDescriptor* fNextChunk; - unsigned fOffsetInFile; - unsigned fNumFrames; - unsigned fFrameSize; - unsigned fFrameDuration; - struct timeval fPresentationTime; // of the start of the data -}; - -class SubsessionBuffer { -public: - SubsessionBuffer(unsigned bufferSize) - : fBufferSize(bufferSize) { - reset(); - fData = new unsigned char[bufferSize]; - } - virtual ~SubsessionBuffer() { delete fData; } - void reset() { fBytesInUse = 0; } - void addBytes(unsigned numBytes) { fBytesInUse += numBytes; } - - unsigned char* dataStart() { return &fData[0]; } - unsigned char* dataEnd() { return &fData[fBytesInUse]; } - unsigned bytesInUse() const { return fBytesInUse; } - unsigned bytesAvailable() const { return fBufferSize - fBytesInUse; } - - void setPresentationTime(struct timeval const& presentationTime) { - fPresentationTime = presentationTime; - } - struct timeval const& presentationTime() const {return fPresentationTime;} - -private: - unsigned fBufferSize; - struct timeval fPresentationTime; - unsigned char* fData; - unsigned fBytesInUse; -}; - -// A 64-bit counter, used below: - -class Count64 { -public: - Count64() { hi = lo = 0; } - - void operator+=(unsigned arg); - - unsigned hi, lo; // each 32 bits -}; - -class SubsessionIOState { -public: - SubsessionIOState(QuickTimeFileSink& sink, MediaSubsession& subsession); - virtual ~SubsessionIOState(); - - Boolean setQTstate(); - void setFinalQTstate(); - - void afterGettingFrame(unsigned packetDataSize, - struct timeval presentationTime); - void onSourceClosure(); - - Boolean syncOK(struct timeval presentationTime); - // returns true iff data is usable despite a sync check - - static void setHintTrack(SubsessionIOState* hintedTrack, - SubsessionIOState* hintTrack); - Boolean isHintTrack() const { return fTrackHintedByUs != NULL; } - Boolean hasHintTrack() const { return fHintTrackForUs != NULL; } - - UsageEnvironment& envir() const { return fOurSink.envir(); } - -public: - static unsigned fCurrentTrackNumber; - unsigned fTrackID; - SubsessionIOState* fHintTrackForUs; SubsessionIOState* fTrackHintedByUs; - - SubsessionBuffer *fBuffer, *fPrevBuffer; - QuickTimeFileSink& fOurSink; - MediaSubsession& fOurSubsession; - - unsigned short fLastPacketRTPSeqNum; - Boolean fOurSourceIsActive; - - Boolean fHaveBeenSynced; // used in synchronizing with other streams - struct timeval fSyncTime; - - Boolean fQTEnableTrack; - unsigned fQTcomponentSubtype; - char const* fQTcomponentName; - typedef unsigned (QuickTimeFileSink::*atomCreationFunc)(); - atomCreationFunc fQTMediaInformationAtomCreator; - atomCreationFunc fQTMediaDataAtomCreator; - char const* fQTAudioDataType; - unsigned short fQTSoundSampleVersion; - unsigned fQTTimeScale; - unsigned fQTTimeUnitsPerSample; - unsigned fQTBytesPerFrame; - unsigned fQTSamplesPerFrame; - // These next fields are derived from the ones above, - // plus the information from each chunk: - unsigned fQTTotNumSamples; - unsigned fQTDurationM; // in media time units - unsigned fQTDurationT; // in track time units - unsigned fTKHD_durationPosn; - // position of the duration in the output 'tkhd' atom - unsigned fQTInitialOffsetDuration; - // if there's a pause at the beginning - - ChunkDescriptor *fHeadChunk, *fTailChunk; - unsigned fNumChunks; - - // Counters to be used in the hint track's 'udta'/'hinf' atom; - struct hinf { - Count64 trpy; - Count64 nump; - Count64 tpyl; - // Is 'maxr' needed? Computing this would be a PITA. ##### - Count64 dmed; - Count64 dimm; - // 'drep' is always 0 - // 'tmin' and 'tmax' are always 0 - unsigned pmax; - unsigned dmax; - } fHINF; - -private: - void useFrame(SubsessionBuffer& buffer); - void useFrameForHinting(unsigned frameSize, - struct timeval presentationTime, - unsigned startSampleNumber); - - // used by the above two routines: - unsigned useFrame1(unsigned sourceDataSize, - struct timeval presentationTime, - unsigned frameDuration, unsigned destFileOffset); - // returns the number of samples in this data - -private: - // A structure used for temporarily storing frame state: - struct { - unsigned frameSize; - struct timeval presentationTime; - unsigned destFileOffset; // used for non-hint tracks only - - // The remaining fields are used for hint tracks only: - unsigned startSampleNumber; - unsigned short seqNum; - unsigned rtpHeader; - unsigned char numSpecialHeaders; // used when our RTP source has special headers - unsigned specialHeaderBytesLength; // ditto - unsigned char specialHeaderBytes[SPECIAL_HEADER_BUFFER_SIZE]; // ditto - unsigned packetSizes[256]; - } fPrevFrameState; -}; - - -////////// QuickTimeFileSink implementation ////////// - -QuickTimeFileSink::QuickTimeFileSink(UsageEnvironment& env, - MediaSession& inputSession, - FILE* outFid, - unsigned bufferSize, - unsigned short movieWidth, - unsigned short movieHeight, - unsigned movieFPS, - Boolean packetLossCompensate, - Boolean syncStreams, - Boolean generateHintTracks, - Boolean generateMP4Format) - : Medium(env), fInputSession(inputSession), fOutFid(outFid), - fBufferSize(bufferSize), fPacketLossCompensate(packetLossCompensate), - fSyncStreams(syncStreams), fGenerateMP4Format(generateMP4Format), - fAreCurrentlyBeingPlayed(False), - fLargestRTPtimestampFrequency(0), - fNumSubsessions(0), fNumSyncedSubsessions(0), - fHaveCompletedOutputFile(False), - fMovieWidth(movieWidth), fMovieHeight(movieHeight), - fMovieFPS(movieFPS), fMaxTrackDurationM(0) { - fNewestSyncTime.tv_sec = fNewestSyncTime.tv_usec = 0; - fFirstDataTime.tv_sec = fFirstDataTime.tv_usec = (unsigned)(~0); - - // Set up I/O state for each input subsession: - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - // Ignore subsessions without a data source: - FramedSource* subsessionSource = subsession->readSource(); - if (subsessionSource == NULL) continue; - - // If "subsession's" SDP description specified screen dimension - // or frame rate parameters, then use these. (Note that this must - // be done before the call to "setQTState()" below.) - if (subsession->videoWidth() != 0) { - fMovieWidth = subsession->videoWidth(); - } - if (subsession->videoHeight() != 0) { - fMovieHeight = subsession->videoHeight(); - } - if (subsession->videoFPS() != 0) { - fMovieFPS = subsession->videoFPS(); - } - - SubsessionIOState* ioState - = new SubsessionIOState(*this, *subsession); - if (ioState == NULL || !ioState->setQTstate()) { - // We're not able to output a QuickTime track for this subsession - delete ioState; ioState = NULL; - continue; - } - subsession->miscPtr = (void*)ioState; - - if (generateHintTracks) { - // Also create a hint track for this track: - SubsessionIOState* hintTrack - = new SubsessionIOState(*this, *subsession); - SubsessionIOState::setHintTrack(ioState, hintTrack); - if (!hintTrack->setQTstate()) { - delete hintTrack; - SubsessionIOState::setHintTrack(ioState, NULL); - } - } - - // Also set a 'BYE' handler for this subsession's RTCP instance: - if (subsession->rtcpInstance() != NULL) { - subsession->rtcpInstance()->setByeHandler(onRTCPBye, ioState); - } - - unsigned rtpTimestampFrequency = subsession->rtpTimestampFrequency(); - if (rtpTimestampFrequency > fLargestRTPtimestampFrequency) { - fLargestRTPtimestampFrequency = rtpTimestampFrequency; - } - - ++fNumSubsessions; - } - - // Use the current time as the file's creation and modification - // time. Use Apple's time format: seconds since January 1, 1904 - - gettimeofday(&fStartTime, NULL); - fAppleCreationTime = fStartTime.tv_sec - 0x83dac000; - - // Begin by writing a "mdat" atom at the start of the file. - // (Later, when we've finished copying data to the file, we'll come - // back and fill in its size.) - fMDATposition = ftell(fOutFid); - addAtomHeader("mdat"); -} - -QuickTimeFileSink::~QuickTimeFileSink() { - completeOutputFile(); - - // Then, delete each active "SubsessionIOState": - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - SubsessionIOState* ioState - = (SubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - delete ioState->fHintTrackForUs; // if any - delete ioState; - } -} - -QuickTimeFileSink* -QuickTimeFileSink::createNew(UsageEnvironment& env, - MediaSession& inputSession, - char const* outputFileName, - unsigned bufferSize, - unsigned short movieWidth, - unsigned short movieHeight, - unsigned movieFPS, - Boolean packetLossCompensate, - Boolean syncStreams, - Boolean generateHintTracks, - Boolean generateMP4Format) { - do { - FILE* fid = OpenOutputFile(env, outputFileName); - if (fid == NULL) break; - - return new QuickTimeFileSink(env, inputSession, fid, bufferSize, - movieWidth, movieHeight, movieFPS, - packetLossCompensate, syncStreams, - generateHintTracks, generateMP4Format); - } while (0); - - return NULL; -} - -Boolean QuickTimeFileSink::startPlaying(afterPlayingFunc* afterFunc, - void* afterClientData) { - // Make sure we're not already being played: - if (fAreCurrentlyBeingPlayed) { - envir().setResultMsg("This sink has already been played"); - return False; - } - - fAreCurrentlyBeingPlayed = True; - fAfterFunc = afterFunc; - fAfterClientData = afterClientData; - - return continuePlaying(); -} - -Boolean QuickTimeFileSink::continuePlaying() { - // Run through each of our input session's 'subsessions', - // asking for a frame from each one: - Boolean haveActiveSubsessions = False; - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - FramedSource* subsessionSource = subsession->readSource(); - if (subsessionSource == NULL) continue; - - if (subsessionSource->isCurrentlyAwaitingData()) continue; - - SubsessionIOState* ioState - = (SubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - haveActiveSubsessions = True; - unsigned char* toPtr = ioState->fBuffer->dataEnd(); - unsigned toSize = ioState->fBuffer->bytesAvailable(); - subsessionSource->getNextFrame(toPtr, toSize, - afterGettingFrame, ioState, - onSourceClosure, ioState); - } - if (!haveActiveSubsessions) { - envir().setResultMsg("No subsessions are currently active"); - return False; - } - - return True; -} - -void QuickTimeFileSink -::afterGettingFrame(void* clientData, unsigned packetDataSize, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/) { - SubsessionIOState* ioState = (SubsessionIOState*)clientData; - if (!ioState->syncOK(presentationTime)) { - // Ignore this data: - ioState->fOurSink.continuePlaying(); - return; - } - ioState->afterGettingFrame(packetDataSize, presentationTime); -} - -void QuickTimeFileSink::onSourceClosure(void* clientData) { - SubsessionIOState* ioState = (SubsessionIOState*)clientData; - ioState->onSourceClosure(); -} - -void QuickTimeFileSink::onSourceClosure1() { - // Check whether *all* of the subsession sources have closed. - // If not, do nothing for now: - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - SubsessionIOState* ioState - = (SubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - if (ioState->fOurSourceIsActive) return; // this source hasn't closed - } - - completeOutputFile(); - - // Call our specified 'after' function: - if (fAfterFunc != NULL) { - (*fAfterFunc)(fAfterClientData); - } -} - -void QuickTimeFileSink::onRTCPBye(void* clientData) { - SubsessionIOState* ioState = (SubsessionIOState*)clientData; - - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - unsigned secsDiff - = timeNow.tv_sec - ioState->fOurSink.fStartTime.tv_sec; - - MediaSubsession& subsession = ioState->fOurSubsession; - ioState->envir() << "Received RTCP \"BYE\" on \"" - << subsession.mediumName() - << "/" << subsession.codecName() - << "\" subsession (after " - << secsDiff << " seconds)\n"; - - // Handle the reception of a RTCP "BYE" as if the source had closed: - ioState->onSourceClosure(); -} - -static Boolean timevalGE(struct timeval const& tv1, - struct timeval const& tv2) { - return (unsigned)tv1.tv_sec > (unsigned)tv2.tv_sec - || (tv1.tv_sec == tv2.tv_sec - && (unsigned)tv1.tv_usec >= (unsigned)tv2.tv_usec); -} - -void QuickTimeFileSink::completeOutputFile() { - if (fHaveCompletedOutputFile || fOutFid == NULL) return; - - // Begin by filling in the initial "mdat" atom with the current - // file size: - unsigned curFileSize = ftell(fOutFid); - setWord(fMDATposition, curFileSize); - - // Then, note the time of the first received data: - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - SubsessionIOState* ioState - = (SubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - ChunkDescriptor* const headChunk = ioState->fHeadChunk; - if (headChunk != NULL - && timevalGE(fFirstDataTime, headChunk->fPresentationTime)) { - fFirstDataTime = headChunk->fPresentationTime; - } - } - - // Then, update the QuickTime-specific state for each active track: - iter.reset(); - while ((subsession = iter.next()) != NULL) { - SubsessionIOState* ioState - = (SubsessionIOState*)(subsession->miscPtr); - if (ioState == NULL) continue; - - ioState->setFinalQTstate(); - // Do the same for a hint track (if any): - if (ioState->hasHintTrack()) { - ioState->fHintTrackForUs->setFinalQTstate(); - } - } - - if (fGenerateMP4Format) { - // Begin with a "ftyp" atom: - addAtom_ftyp(); - } - - // Then, add a "moov" atom for the file metadata: - addAtom_moov(); - - // We're done: - fHaveCompletedOutputFile = True; -} - - -////////// SubsessionIOState, ChunkDescriptor implementation /////////// - -unsigned SubsessionIOState::fCurrentTrackNumber = 0; - -SubsessionIOState::SubsessionIOState(QuickTimeFileSink& sink, - MediaSubsession& subsession) - : fHintTrackForUs(NULL), fTrackHintedByUs(NULL), - fOurSink(sink), fOurSubsession(subsession), - fLastPacketRTPSeqNum(0), fHaveBeenSynced(False), fQTTotNumSamples(0), - fHeadChunk(NULL), fTailChunk(NULL), fNumChunks(0) { - fTrackID = ++fCurrentTrackNumber; - - fBuffer = new SubsessionBuffer(fOurSink.fBufferSize); - fPrevBuffer = sink.fPacketLossCompensate - ? new SubsessionBuffer(fOurSink.fBufferSize) : NULL; - - FramedSource* subsessionSource = subsession.readSource(); - fOurSourceIsActive = subsessionSource != NULL; - - fPrevFrameState.presentationTime.tv_sec = 0; - fPrevFrameState.presentationTime.tv_usec = 0; - fPrevFrameState.seqNum = 0; -} - -SubsessionIOState::~SubsessionIOState() { - delete fBuffer; delete fPrevBuffer; - delete fHeadChunk; -} - -Boolean SubsessionIOState::setQTstate() { - char const* noCodecWarning1 = "Warning: We don't implement a QuickTime "; - char const* noCodecWarning2 = " Media Data Type for the \""; - char const* noCodecWarning3 = "\" track, so we'll insert a dummy \"????\" Media Data Atom instead. A separate, codec-specific editing pass will be needed before this track can be played.\n"; - Boolean supportPartiallyOnly = False; - - do { - fQTEnableTrack = True; // enable this track in the movie by default - fQTTimeScale = fOurSubsession.rtpTimestampFrequency(); // by default - fQTTimeUnitsPerSample = 1; // by default - fQTBytesPerFrame = 0; - // by default - indicates that the whole packet data is a frame - fQTSamplesPerFrame = 1; // by default - - // Make sure our subsession's medium is one that we know how to - // represent in a QuickTime file: - if (isHintTrack()) { - // Hint tracks are treated specially - fQTEnableTrack = False; // hint tracks are marked as inactive - fQTcomponentSubtype = fourChar('h','i','n','t'); - fQTcomponentName = "hint media handler"; - fQTMediaInformationAtomCreator = &QuickTimeFileSink::addAtom_gmhd; - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_rtp; - } else if (strcmp(fOurSubsession.mediumName(), "audio") == 0) { - fQTcomponentSubtype = fourChar('s','o','u','n'); - fQTcomponentName = "Apple Sound Media Handler"; - fQTMediaInformationAtomCreator = &QuickTimeFileSink::addAtom_smhd; - fQTMediaDataAtomCreator - = &QuickTimeFileSink::addAtom_soundMediaGeneral; // by default - fQTSoundSampleVersion = 0; // by default - - // Make sure that our subsession's codec is one that we can handle: - if (strcmp(fOurSubsession.codecName(), "X-QT") == 0 || - strcmp(fOurSubsession.codecName(), "X-QUICKTIME") == 0) { - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_genericMedia; - } else if (strcmp(fOurSubsession.codecName(), "PCMU") == 0) { - fQTAudioDataType = "ulaw"; - fQTBytesPerFrame = 1; - } else if (strcmp(fOurSubsession.codecName(), "GSM") == 0) { - fQTAudioDataType = "agsm"; - fQTBytesPerFrame = 33; - fQTSamplesPerFrame = 160; - } else if (strcmp(fOurSubsession.codecName(), "PCMA") == 0) { - fQTAudioDataType = "alaw"; - fQTBytesPerFrame = 1; - } else if (strcmp(fOurSubsession.codecName(), "QCELP") == 0) { - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_Qclp; - fQTSamplesPerFrame = 160; - } else if (strcmp(fOurSubsession.codecName(), "MPEG4-GENERIC") == 0 || - strcmp(fOurSubsession.codecName(), "MP4A-LATM") == 0) { - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_mp4a; - fQTTimeUnitsPerSample = 1024; // QT considers each frame to be a 'sample' - // The time scale (frequency) comes from the 'config' information. - // It might be different from the RTP timestamp frequency (e.g., aacPlus). - unsigned frequencyFromConfig - = samplingFrequencyFromAudioSpecificConfig(fOurSubsession.fmtp_config()); - if (frequencyFromConfig != 0) fQTTimeScale = frequencyFromConfig; - } else { - envir() << noCodecWarning1 << "Audio" << noCodecWarning2 - << fOurSubsession.codecName() << noCodecWarning3; - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_dummy; - fQTEnableTrack = False; // disable this track in the movie - } - } else if (strcmp(fOurSubsession.mediumName(), "video") == 0) { - fQTcomponentSubtype = fourChar('v','i','d','e'); - fQTcomponentName = "Apple Video Media Handler"; - fQTMediaInformationAtomCreator = &QuickTimeFileSink::addAtom_vmhd; - - // Make sure that our subsession's codec is one that we can handle: - if (strcmp(fOurSubsession.codecName(), "X-QT") == 0 || - strcmp(fOurSubsession.codecName(), "X-QUICKTIME") == 0) { - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_genericMedia; - } else if (strcmp(fOurSubsession.codecName(), "H263-1998") == 0 || - strcmp(fOurSubsession.codecName(), "H263-2000") == 0) { - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_h263; - fQTTimeScale = 600; - fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS; - } else if (strcmp(fOurSubsession.codecName(), "MP4V-ES") == 0) { - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_mp4v; - fQTTimeScale = 600; - fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS; - } else { - envir() << noCodecWarning1 << "Video" << noCodecWarning2 - << fOurSubsession.codecName() << noCodecWarning3; - fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_dummy; - fQTEnableTrack = False; // disable this track in the movie - } - } else { - envir() << "Warning: We don't implement a QuickTime Media Handler for media type \"" - << fOurSubsession.mediumName() << "\""; - break; - } - - if (supportPartiallyOnly) { - envir() << "Warning: We don't have sufficient codec-specific information (e.g., sample sizes) to fully generate the \"" - << fOurSubsession.mediumName() << "/" - << fOurSubsession.codecName() - << "\" track, so we'll disable this track in the movie. A separate, codec-specific editing pass will be needed before this track can be played\n"; - fQTEnableTrack = False; // disable this track in the movie - } - - return True; - } while (0); - - envir() << ", so a track for the \"" << fOurSubsession.mediumName() - << "/" << fOurSubsession.codecName() - << "\" subsession will not be included in the output QuickTime file\n"; - return False; -} - -void SubsessionIOState::setFinalQTstate() { - // Compute derived parameters, by running through the list of chunks: - fQTDurationT = 0; - - ChunkDescriptor* chunk = fHeadChunk; - while (chunk != NULL) { - unsigned const numFrames = chunk->fNumFrames; - unsigned const dur = numFrames*chunk->fFrameDuration; - fQTDurationT += dur; - - chunk = chunk->fNextChunk; - } - - // Convert this duration from track to movie time scale: - double scaleFactor = fOurSink.movieTimeScale()/(double)fQTTimeScale; - fQTDurationM = (unsigned)(fQTDurationT*scaleFactor); - - if (fQTDurationM > fOurSink.fMaxTrackDurationM) { - fOurSink.fMaxTrackDurationM = fQTDurationM; - } -} - -void SubsessionIOState::afterGettingFrame(unsigned packetDataSize, - struct timeval presentationTime) { - // Begin by checking whether there was a gap in the RTP stream. - // If so, try to compensate for this (if desired): - unsigned short rtpSeqNum - = fOurSubsession.rtpSource()->curPacketRTPSeqNum(); - if (fOurSink.fPacketLossCompensate && fPrevBuffer->bytesInUse() > 0) { - short seqNumGap = rtpSeqNum - fLastPacketRTPSeqNum; - for (short i = 1; i < seqNumGap; ++i) { - // Insert a copy of the previous frame, to compensate for the loss: - useFrame(*fPrevBuffer); - } - } - fLastPacketRTPSeqNum = rtpSeqNum; - - // Now, continue working with the frame that we just got - if (fBuffer->bytesInUse() == 0) { - fBuffer->setPresentationTime(presentationTime); - } - fBuffer->addBytes(packetDataSize); - - // If our RTP source is a "QuickTimeGenericRTPSource", then - // use its 'qtState' to set some parameters that we need: - if (fQTMediaDataAtomCreator == &QuickTimeFileSink::addAtom_genericMedia){ - QuickTimeGenericRTPSource* rtpSource - = (QuickTimeGenericRTPSource*)fOurSubsession.rtpSource(); - QuickTimeGenericRTPSource::QTState& qtState = rtpSource->qtState; - fQTTimeScale = qtState.timescale; - if (qtState.width != 0) { - fOurSink.fMovieWidth = qtState.width; - } - if (qtState.height != 0) { - fOurSink.fMovieHeight = qtState.height; - } - - // Also, if the media type in the "sdAtom" is one that we recognize - // to have a special parameters, then fix this here: - if (qtState.sdAtomSize >= 8) { - char const* atom = qtState.sdAtom; - unsigned mediaType = fourChar(atom[4],atom[5],atom[6],atom[7]); - switch (mediaType) { - case fourChar('a','g','s','m'): { - fQTBytesPerFrame = 33; - fQTSamplesPerFrame = 160; - break; - } - case fourChar('Q','c','l','p'): { - fQTBytesPerFrame = 35; - fQTSamplesPerFrame = 160; - break; - } - case fourChar('H','c','l','p'): { - fQTBytesPerFrame = 17; - fQTSamplesPerFrame = 160; - break; - } - case fourChar('h','2','6','3'): { - fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS; - break; - } - } - } - } else if (fQTMediaDataAtomCreator == &QuickTimeFileSink::addAtom_Qclp) { - // For QCELP data, make a note of the frame size (even though it's the - // same as the packet data size), because it varies depending on the - // 'rate' of the stream, and this size gets used later when setting up - // the 'Qclp' QuickTime atom: - fQTBytesPerFrame = packetDataSize; - } - - useFrame(*fBuffer); - if (fOurSink.fPacketLossCompensate) { - // Save this frame, in case we need it for recovery: - SubsessionBuffer* tmp = fPrevBuffer; // assert: != NULL - fPrevBuffer = fBuffer; - fBuffer = tmp; - } - fBuffer->reset(); // for the next input - - // Now, try getting more frames: - fOurSink.continuePlaying(); -} - -void SubsessionIOState::useFrame(SubsessionBuffer& buffer) { - unsigned char* const frameSource = buffer.dataStart(); - unsigned const frameSize = buffer.bytesInUse(); - struct timeval const& presentationTime = buffer.presentationTime(); - unsigned const destFileOffset = ftell(fOurSink.fOutFid); - unsigned sampleNumberOfFrameStart = fQTTotNumSamples + 1; - - // If we're not syncing streams, or this subsession is not video, then - // just give this frame a fixed duration: - if (!fOurSink.fSyncStreams - || fQTcomponentSubtype != fourChar('v','i','d','e')) { - unsigned const frameDuration = fQTTimeUnitsPerSample*fQTSamplesPerFrame; - - fQTTotNumSamples += useFrame1(frameSize, presentationTime, - frameDuration, destFileOffset); - } else { - // For synced video streams, we use the difference between successive - // frames' presentation times as the 'frame duration'. So, record - // information about the *previous* frame: - struct timeval const& ppt = fPrevFrameState.presentationTime; //abbrev - if (ppt.tv_sec != 0 || ppt.tv_usec != 0) { - // There has been a previous frame. - double duration = (presentationTime.tv_sec - ppt.tv_sec) - + (presentationTime.tv_usec - ppt.tv_usec)/1000000.0; - if (duration < 0.0) duration = 0.0; - unsigned frameDuration - = (unsigned)((2*duration*fQTTimeScale+1)/2); // round - - unsigned numSamples - = useFrame1(fPrevFrameState.frameSize, ppt, - frameDuration, fPrevFrameState.destFileOffset); - fQTTotNumSamples += numSamples; - sampleNumberOfFrameStart = fQTTotNumSamples + 1; - } - - // Remember the current frame for next time: - fPrevFrameState.frameSize = frameSize; - fPrevFrameState.presentationTime = presentationTime; - fPrevFrameState.destFileOffset = destFileOffset; - } - - // Write the data into the file: - fwrite(frameSource, 1, frameSize, fOurSink.fOutFid); - - // If we have a hint track, then write to it also: - if (hasHintTrack()) { - // Because presentation times are used for RTP packet timestamps, - // we don't starting writing to the hint track until we've been synced: - if (!fHaveBeenSynced) { - fHaveBeenSynced - = fOurSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP(); - } - if (fHaveBeenSynced) { - fHintTrackForUs->useFrameForHinting(frameSize, presentationTime, - sampleNumberOfFrameStart); - } - } -} - -void SubsessionIOState::useFrameForHinting(unsigned frameSize, - struct timeval presentationTime, - unsigned startSampleNumber) { - // At this point, we have a single, combined frame - not individual packets. - // For the hint track, we need to split the frame back up into separate packets. - // However, for some RTP sources, then we also need to reuse the special - // header bytes that were at the start of each of the RTP packets. - Boolean hack263 = strcmp(fOurSubsession.codecName(), "H263-1998") == 0; - Boolean hackm4a_generic = strcmp(fOurSubsession.mediumName(), "audio") == 0 - && strcmp(fOurSubsession.codecName(), "MPEG4-GENERIC") == 0; - Boolean hackm4a_latm = strcmp(fOurSubsession.mediumName(), "audio") == 0 - && strcmp(fOurSubsession.codecName(), "MP4A-LATM") == 0; - Boolean hackm4a = hackm4a_generic || hackm4a_latm; - Boolean haveSpecialHeaders = (hack263 || hackm4a_generic); - - // If there has been a previous frame, then output a 'hint sample' for it. - // (We use the current frame's presentation time to compute the previous - // hint sample's duration.) - RTPSource* const rs = fOurSubsession.rtpSource(); // abbrev - struct timeval const& ppt = fPrevFrameState.presentationTime; //abbrev - if (ppt.tv_sec != 0 || ppt.tv_usec != 0) { - double duration = (presentationTime.tv_sec - ppt.tv_sec) - + (presentationTime.tv_usec - ppt.tv_usec)/1000000.0; - if (duration < 0.0) duration = 0.0; - unsigned msDuration = (unsigned)(duration*1000); // milliseconds - if (msDuration > fHINF.dmax) fHINF.dmax = msDuration; - unsigned hintSampleDuration - = (unsigned)((2*duration*fQTTimeScale+1)/2); // round - if (hackm4a) { - // Because multiple AAC frames can appear in a RTP packet, the presentation - // times of the second and subsequent frames will not be accurate. - // So, use the known "hintSampleDuration" instead: - hintSampleDuration = fTrackHintedByUs->fQTTimeUnitsPerSample; - - // Also, if the 'time scale' was different from the RTP timestamp frequency, - // (as can happen with aacPlus), then we need to scale "hintSampleDuration" - // accordingly: - if (fTrackHintedByUs->fQTTimeScale != fOurSubsession.rtpTimestampFrequency()) { - unsigned const scalingFactor - = fOurSubsession.rtpTimestampFrequency()/fTrackHintedByUs->fQTTimeScale ; - hintSampleDuration *= scalingFactor; - } - } - - unsigned const hintSampleDestFileOffset = ftell(fOurSink.fOutFid); - - unsigned const maxPacketSize = 1450; - unsigned short numPTEntries - = (fPrevFrameState.frameSize + (maxPacketSize-1))/maxPacketSize; // normal case - unsigned char* immediateDataPtr = NULL; - unsigned immediateDataBytesRemaining = 0; - if (haveSpecialHeaders) { // special case - numPTEntries = fPrevFrameState.numSpecialHeaders; - immediateDataPtr = fPrevFrameState.specialHeaderBytes; - immediateDataBytesRemaining - = fPrevFrameState.specialHeaderBytesLength; - } - unsigned hintSampleSize - = fOurSink.addHalfWord(numPTEntries);// Entry count - hintSampleSize += fOurSink.addHalfWord(0x0000); // Reserved - - unsigned offsetWithinSample = 0; - for (unsigned i = 0; i < numPTEntries; ++i) { - // Output a Packet Table entry (representing a single RTP packet): - unsigned short numDTEntries = 1; - unsigned short seqNum = fPrevFrameState.seqNum++; - // Note: This assumes that the input stream had no packets lost ##### - unsigned rtpHeader = fPrevFrameState.rtpHeader; - if (i+1 < numPTEntries) { - // This is not the last RTP packet, so clear the marker bit: - rtpHeader &=~ (1<<23); - } - unsigned dataFrameSize = (i+1 < numPTEntries) - ? maxPacketSize : fPrevFrameState.frameSize - i*maxPacketSize; // normal case - unsigned sampleNumber = fPrevFrameState.startSampleNumber; - - unsigned char immediateDataLen = 0; - if (haveSpecialHeaders) { // special case - ++numDTEntries; // to include a Data Table entry for the special hdr - if (immediateDataBytesRemaining > 0) { - if (hack263) { - immediateDataLen = *immediateDataPtr++; - --immediateDataBytesRemaining; - if (immediateDataLen > immediateDataBytesRemaining) { - // shouldn't happen (length byte was bad) - immediateDataLen = immediateDataBytesRemaining; - } - } else { - immediateDataLen = fPrevFrameState.specialHeaderBytesLength; - } - } - dataFrameSize = fPrevFrameState.packetSizes[i] - immediateDataLen; - - if (hack263) { - Boolean PbitSet - = immediateDataLen >= 1 && (immediateDataPtr[0]&0x4) != 0; - if (PbitSet) { - offsetWithinSample += 2; // to omit the two leading 0 bytes - } - } - } - - // Output the Packet Table: - hintSampleSize += fOurSink.addWord(0); // Relative transmission time - hintSampleSize += fOurSink.addWord(rtpHeader|seqNum); - // RTP header info + RTP sequence number - hintSampleSize += fOurSink.addHalfWord(0x0000); // Flags - hintSampleSize += fOurSink.addHalfWord(numDTEntries); // Entry count - unsigned totalPacketSize = 0; - - // Output the Data Table: - if (haveSpecialHeaders) { - // use the "Immediate Data" format (1): - hintSampleSize += fOurSink.addByte(1); // Source - unsigned char len = immediateDataLen > 14 ? 14 : immediateDataLen; - hintSampleSize += fOurSink.addByte(len); // Length - totalPacketSize += len; fHINF.dimm += len; - unsigned char j; - for (j = 0; j < len; ++j) { - hintSampleSize += fOurSink.addByte(immediateDataPtr[j]); // Data - } - for (j = len; j < 14; ++j) { - hintSampleSize += fOurSink.addByte(0); // Data (padding) - } - - immediateDataPtr += immediateDataLen; - immediateDataBytesRemaining -= immediateDataLen; - } - // use the "Sample Data" format (2): - hintSampleSize += fOurSink.addByte(2); // Source - hintSampleSize += fOurSink.addByte(0); // Track ref index - hintSampleSize += fOurSink.addHalfWord(dataFrameSize); // Length - totalPacketSize += dataFrameSize; fHINF.dmed += dataFrameSize; - hintSampleSize += fOurSink.addWord(sampleNumber); // Sample number - hintSampleSize += fOurSink.addWord(offsetWithinSample); // Offset - // Get "bytes|samples per compression block" from the hinted track: - unsigned short const bytesPerCompressionBlock - = fTrackHintedByUs->fQTBytesPerFrame; - unsigned short const samplesPerCompressionBlock - = fTrackHintedByUs->fQTSamplesPerFrame; - hintSampleSize += fOurSink.addHalfWord(bytesPerCompressionBlock); - hintSampleSize += fOurSink.addHalfWord(samplesPerCompressionBlock); - - offsetWithinSample += dataFrameSize;// for the next iteration (if any) - - // Tally statistics for this packet: - fHINF.nump += 1; - fHINF.tpyl += totalPacketSize; - totalPacketSize += 12; // add in the size of the RTP header - fHINF.trpy += totalPacketSize; - if (totalPacketSize > fHINF.pmax) fHINF.pmax = totalPacketSize; - } - - // Make note of this completed hint sample frame: - fQTTotNumSamples += useFrame1(hintSampleSize, ppt, hintSampleDuration, - hintSampleDestFileOffset); - } - - // Remember this frame for next time: - fPrevFrameState.frameSize = frameSize; - fPrevFrameState.presentationTime = presentationTime; - fPrevFrameState.startSampleNumber = startSampleNumber; - fPrevFrameState.rtpHeader - = rs->curPacketMarkerBit()<<23 - | (rs->rtpPayloadFormat()&0x7F)<<16; - if (hack263) { - H263plusVideoRTPSource* rs_263 = (H263plusVideoRTPSource*)rs; - fPrevFrameState.numSpecialHeaders = rs_263->fNumSpecialHeaders; - fPrevFrameState.specialHeaderBytesLength = rs_263->fSpecialHeaderBytesLength; - unsigned i; - for (i = 0; i < rs_263->fSpecialHeaderBytesLength; ++i) { - fPrevFrameState.specialHeaderBytes[i] = rs_263->fSpecialHeaderBytes[i]; - } - for (i = 0; i < rs_263->fNumSpecialHeaders; ++i) { - fPrevFrameState.packetSizes[i] = rs_263->fPacketSizes[i]; - } - } else if (hackm4a_generic) { - // Synthesize a special header, so that this frame can be in its own RTP packet. - unsigned const sizeLength = fOurSubsession.fmtp_sizelength(); - unsigned const indexLength = fOurSubsession.fmtp_indexlength(); - if (sizeLength + indexLength != 16) { - envir() << "Warning: unexpected 'sizeLength' " << sizeLength - << " and 'indexLength' " << indexLength - << "seen when creating hint track\n"; - } - fPrevFrameState.numSpecialHeaders = 1; - fPrevFrameState.specialHeaderBytesLength = 4; - fPrevFrameState.specialHeaderBytes[0] = 0; // AU_headers_length (high byte) - fPrevFrameState.specialHeaderBytes[1] = 16; // AU_headers_length (low byte) - fPrevFrameState.specialHeaderBytes[2] = ((frameSize<>8; - fPrevFrameState.specialHeaderBytes[3] = (frameSize<extendChunk(destFileOffset, sourceDataSize, - frameSize, frameDuration, - presentationTime); - } - if (newTailChunk != fTailChunk) { - // This data created a new chunk, rather than extending the old one - ++fNumChunks; - fTailChunk = newTailChunk; - } - - return numSamples; -} - -void SubsessionIOState::onSourceClosure() { - fOurSourceIsActive = False; - fOurSink.onSourceClosure1(); -} - -Boolean SubsessionIOState::syncOK(struct timeval presentationTime) { - QuickTimeFileSink& s = fOurSink; // abbreviation - if (!s.fSyncStreams) return True; // we don't care - - if (s.fNumSyncedSubsessions < s.fNumSubsessions) { - // Not all subsessions have yet been synced. Check whether ours was - // one of the unsynced ones, and, if so, whether it is now synced: - if (!fHaveBeenSynced) { - // We weren't synchronized before - if (fOurSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP()) { - // But now we are - fHaveBeenSynced = True; - fSyncTime = presentationTime; - ++s.fNumSyncedSubsessions; - - if (timevalGE(fSyncTime, s.fNewestSyncTime)) { - s.fNewestSyncTime = fSyncTime; - } - } - } - } - - // Check again whether all subsessions have been synced: - if (s.fNumSyncedSubsessions < s.fNumSubsessions) return False; - - // Allow this data if it is more recent than the newest sync time: - return timevalGE(presentationTime, s.fNewestSyncTime); -} - -void SubsessionIOState::setHintTrack(SubsessionIOState* hintedTrack, - SubsessionIOState* hintTrack) { - if (hintedTrack != NULL) hintedTrack->fHintTrackForUs = hintTrack; - if (hintTrack != NULL) hintTrack->fTrackHintedByUs = hintedTrack; -} - -void Count64::operator+=(unsigned arg) { - unsigned newLo = lo + arg; - if (newLo < lo) { // lo has overflowed - ++hi; - } - lo = newLo; -} - -ChunkDescriptor -::ChunkDescriptor(unsigned offsetInFile, unsigned size, - unsigned frameSize, unsigned frameDuration, - struct timeval presentationTime) - : fNextChunk(NULL), fOffsetInFile(offsetInFile), - fNumFrames(size/frameSize), - fFrameSize(frameSize), fFrameDuration(frameDuration), - fPresentationTime(presentationTime) { -} - -ChunkDescriptor::~ChunkDescriptor() { - delete fNextChunk; -} - -ChunkDescriptor* ChunkDescriptor -::extendChunk(unsigned newOffsetInFile, unsigned newSize, - unsigned newFrameSize, unsigned newFrameDuration, - struct timeval newPresentationTime) { - // First, check whether the new space is just at the end of this - // existing chunk: - if (newOffsetInFile == fOffsetInFile + fNumFrames*fFrameSize) { - // We can extend this existing chunk, provided that the frame size - // and frame duration have not changed: - if (newFrameSize == fFrameSize && newFrameDuration == fFrameDuration) { - fNumFrames += newSize/fFrameSize; - return this; - } - } - - // We'll allocate a new ChunkDescriptor, and link it to the end of us: - ChunkDescriptor* newDescriptor - = new ChunkDescriptor(newOffsetInFile, newSize, - newFrameSize, newFrameDuration, - newPresentationTime); - - fNextChunk = newDescriptor; - - return newDescriptor; -} - - -////////// QuickTime-specific implementation ////////// - -unsigned QuickTimeFileSink::addWord(unsigned word) { - addByte(word>>24); addByte(word>>16); - addByte(word>>8); addByte(word); - - return 4; -} - -unsigned QuickTimeFileSink::addHalfWord(unsigned short halfWord) { - addByte((unsigned char)(halfWord>>8)); addByte((unsigned char)halfWord); - - return 2; -} - -unsigned QuickTimeFileSink::addZeroWords(unsigned numWords) { - for (unsigned i = 0; i < numWords; ++i) { - addWord(0); - } - - return numWords*4; -} - -unsigned QuickTimeFileSink::add4ByteString(char const* str) { - addByte(str[0]); addByte(str[1]); addByte(str[2]); addByte(str[3]); - - return 4; -} - -unsigned QuickTimeFileSink::addArbitraryString(char const* str, - Boolean oneByteLength) { - unsigned size = 0; - if (oneByteLength) { - // Begin with a byte containing the string length: - unsigned strLength = strlen(str); - if (strLength >= 256) { - envir() << "QuickTimeFileSink::addArbitraryString(\"" - << str << "\") saw string longer than we know how to handle (" - << strLength << "\n"; - } - size += addByte((unsigned char)strLength); - } - - while (*str != '\0') { - size += addByte(*str++); - } - - return size; -} - -unsigned QuickTimeFileSink::addAtomHeader(char const* atomName) { - // Output a placeholder for the 4-byte size: - addWord(0); - - // Output the 4-byte atom name: - add4ByteString(atomName); - - return 8; -} - -void QuickTimeFileSink::setWord(unsigned filePosn, unsigned size) { - do { - if (fseek(fOutFid, filePosn, SEEK_SET) < 0) break; - addWord(size); - if (fseek(fOutFid, 0, SEEK_END) < 0) break; // go back to where we were - - return; - } while (0); - - // One of the fseek()s failed, probable because we're not a seekable file - envir() << "QuickTimeFileSink::setWord(): fseek failed (err " - << envir().getErrno() << ")\n"; -} - -// Methods for writing particular atoms. Note the following macros: - -#define addAtom(name) \ - unsigned QuickTimeFileSink::addAtom_##name() { \ - unsigned initFilePosn = ftell(fOutFid); \ - unsigned size = addAtomHeader("" #name "") - -#define addAtomEnd \ - setWord(initFilePosn, size); \ - return size; \ -} - -addAtom(ftyp); - size += add4ByteString("mp42"); - size += addWord(0x00000000); - size += add4ByteString("mp42"); - size += add4ByteString("isom"); -addAtomEnd; - -addAtom(moov); - size += addAtom_mvhd(); - - if (fGenerateMP4Format) { - size += addAtom_iods(); - } - - // Add a 'trak' atom for each subsession: - // (For some unknown reason, QuickTime Player (5.0 at least) - // doesn't display the movie correctly unless the audio track - // (if present) appears before the video track. So ensure this here.) - MediaSubsessionIterator iter(fInputSession); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - fCurrentIOState = (SubsessionIOState*)(subsession->miscPtr); - if (fCurrentIOState == NULL) continue; - if (strcmp(subsession->mediumName(), "audio") != 0) continue; - - size += addAtom_trak(); - - if (fCurrentIOState->hasHintTrack()) { - // This track has a hint track; output it also: - fCurrentIOState = fCurrentIOState->fHintTrackForUs; - size += addAtom_trak(); - } - } - iter.reset(); - while ((subsession = iter.next()) != NULL) { - fCurrentIOState = (SubsessionIOState*)(subsession->miscPtr); - if (fCurrentIOState == NULL) continue; - if (strcmp(subsession->mediumName(), "audio") == 0) continue; - - size += addAtom_trak(); - - if (fCurrentIOState->hasHintTrack()) { - // This track has a hint track; output it also: - fCurrentIOState = fCurrentIOState->fHintTrackForUs; - size += addAtom_trak(); - } - } -addAtomEnd; - -addAtom(mvhd); - size += addWord(0x00000000); // Version + Flags - size += addWord(fAppleCreationTime); // Creation time - size += addWord(fAppleCreationTime); // Modification time - - // For the "Time scale" field, use the largest RTP timestamp frequency - // that we saw in any of the subsessions. - size += addWord(movieTimeScale()); // Time scale - - unsigned const duration = fMaxTrackDurationM; - fMVHD_durationPosn = ftell(fOutFid); - size += addWord(duration); // Duration - - size += addWord(0x00010000); // Preferred rate - size += addWord(0x01000000); // Preferred volume + Reserved[0] - size += addZeroWords(2); // Reserved[1-2] - size += addWord(0x00010000); // matrix top left corner - size += addZeroWords(3); // matrix - size += addWord(0x00010000); // matrix center - size += addZeroWords(3); // matrix - size += addWord(0x40000000); // matrix bottom right corner - size += addZeroWords(6); // various time fields - size += addWord(SubsessionIOState::fCurrentTrackNumber+1);// Next track ID -addAtomEnd; - -addAtom(iods); - size += addWord(0x00000000); // Version + Flags - size += addWord(0x10808080); - size += addWord(0x07004FFF); - size += addWord(0xFF0FFFFF); -addAtomEnd; - -addAtom(trak); - size += addAtom_tkhd(); - - // If we're synchronizing the media streams (or are a hint track), - // add an edit list that helps do this: - if (fCurrentIOState->fHeadChunk != NULL - && (fSyncStreams || fCurrentIOState->isHintTrack())) { - size += addAtom_edts(); - } - - // If we're generating a hint track, add a 'tref' atom: - if (fCurrentIOState->isHintTrack()) size += addAtom_tref(); - - size += addAtom_mdia(); - - // If we're generating a hint track, add a 'udta' atom: - if (fCurrentIOState->isHintTrack()) size += addAtom_udta(); -addAtomEnd; - -addAtom(tkhd); - if (fCurrentIOState->fQTEnableTrack) { - size += addWord(0x0000000F); // Version + Flags - } else { - // Disable this track in the movie: - size += addWord(0x00000000); // Version + Flags - } - size += addWord(fAppleCreationTime); // Creation time - size += addWord(fAppleCreationTime); // Modification time - size += addWord(fCurrentIOState->fTrackID); // Track ID - size += addWord(0x00000000); // Reserved - - unsigned const duration = fCurrentIOState->fQTDurationM; // movie units - fCurrentIOState->fTKHD_durationPosn = ftell(fOutFid); - size += addWord(duration); // Duration - size += addZeroWords(3); // Reserved+Layer+Alternate grp - size += addWord(0x01000000); // Volume + Reserved - size += addWord(0x00010000); // matrix top left corner - size += addZeroWords(3); // matrix - size += addWord(0x00010000); // matrix center - size += addZeroWords(3); // matrix - size += addWord(0x40000000); // matrix bottom right corner - if (strcmp(fCurrentIOState->fOurSubsession.mediumName(), "video") == 0) { - size += addWord(fMovieWidth<<16); // Track width - size += addWord(fMovieHeight<<16); // Track height - } else { - size += addZeroWords(2); // not video: leave width and height fields zero - } -addAtomEnd; - -addAtom(edts); - size += addAtom_elst(); -addAtomEnd; - -#define addEdit1(duration,trackPosition) do { \ - unsigned trackDuration \ - = (unsigned) ((2*(duration)*movieTimeScale()+1)/2); \ - /* in movie time units */ \ - size += addWord(trackDuration); /* Track duration */ \ - totalDurationOfEdits += trackDuration; \ - size += addWord(trackPosition); /* Media time */ \ - size += addWord(0x00010000); /* Media rate (1x) */ \ - ++numEdits; \ -} while (0) -#define addEdit(duration) addEdit1((duration),editTrackPosition) -#define addEmptyEdit(duration) addEdit1((duration),(~0)) - -addAtom(elst); - size += addWord(0x00000000); // Version + Flags - - // Add a dummy "Number of entries" field - // (and remember its position). We'll fill this field in later: - unsigned numEntriesPosition = ftell(fOutFid); - size += addWord(0); // dummy for "Number of entries" - unsigned numEdits = 0; - unsigned totalDurationOfEdits = 0; // in movie time units - - // Run through our chunks, looking at their presentation times. - // From these, figure out the edits that need to be made to keep - // the track media data in sync with the presentation times. - - double const syncThreshold = 0.1; // 100 ms - // don't allow the track to get out of sync by more than this - - struct timeval editStartTime = fFirstDataTime; - unsigned editTrackPosition = 0; - unsigned currentTrackPosition = 0; - double trackDurationOfEdit = 0.0; - unsigned chunkDuration = 0; - - ChunkDescriptor* chunk = fCurrentIOState->fHeadChunk; - while (chunk != NULL) { - struct timeval const& chunkStartTime = chunk->fPresentationTime; - double movieDurationOfEdit - = (chunkStartTime.tv_sec - editStartTime.tv_sec) - + (chunkStartTime.tv_usec - editStartTime.tv_usec)/1000000.0; - trackDurationOfEdit = (currentTrackPosition-editTrackPosition) - / (double)(fCurrentIOState->fQTTimeScale); - - double outOfSync = movieDurationOfEdit - trackDurationOfEdit; - - if (outOfSync > syncThreshold) { - // The track's data is too short, so end this edit, add a new - // 'empty' edit after it, and start a new edit - // (at the current track posn.): - if (trackDurationOfEdit > 0.0) addEdit(trackDurationOfEdit); - addEmptyEdit(outOfSync); - - editStartTime = chunkStartTime; - editTrackPosition = currentTrackPosition; - } else if (outOfSync < -syncThreshold) { - // The track's data is too long, so end this edit, and start - // a new edit (pointing at the current track posn.): - if (movieDurationOfEdit > 0.0) addEdit(movieDurationOfEdit); - - editStartTime = chunkStartTime; - editTrackPosition = currentTrackPosition; - } - - // Note the duration of this chunk: - unsigned numChannels = fCurrentIOState->fOurSubsession.numChannels(); - chunkDuration = chunk->fNumFrames*chunk->fFrameDuration/numChannels; - currentTrackPosition += chunkDuration; - - chunk = chunk->fNextChunk; - } - - // Write out the final edit - trackDurationOfEdit - += (double)chunkDuration/fCurrentIOState->fQTTimeScale; - if (trackDurationOfEdit > 0.0) addEdit(trackDurationOfEdit); - - // Now go back and fill in the "Number of entries" field: - setWord(numEntriesPosition, numEdits); - - // Also, if the sum of all of the edit durations exceeds the - // track duration that we already computed (from sample durations), - // then reset the track duration to this new value: - if (totalDurationOfEdits > fCurrentIOState->fQTDurationM) { - fCurrentIOState->fQTDurationM = totalDurationOfEdits; - setWord(fCurrentIOState->fTKHD_durationPosn, totalDurationOfEdits); - - // Also, check whether the overall movie duration needs to change: - if (totalDurationOfEdits > fMaxTrackDurationM) { - fMaxTrackDurationM = totalDurationOfEdits; - setWord(fMVHD_durationPosn, totalDurationOfEdits); - } - - // Also, convert to track time scale: - double scaleFactor - = fCurrentIOState->fQTTimeScale/(double)movieTimeScale(); - fCurrentIOState->fQTDurationT - = (unsigned)(totalDurationOfEdits*scaleFactor); - } -addAtomEnd; - -addAtom(tref); - size += addAtom_hint(); -addAtomEnd; - -addAtom(hint); - SubsessionIOState* hintedTrack = fCurrentIOState->fTrackHintedByUs; - // Assert: hintedTrack != NULL - size += addWord(hintedTrack->fTrackID); -addAtomEnd; - -addAtom(mdia); - size += addAtom_mdhd(); - size += addAtom_hdlr(); - size += addAtom_minf(); -addAtomEnd; - -addAtom(mdhd); - size += addWord(0x00000000); // Version + Flags - size += addWord(fAppleCreationTime); // Creation time - size += addWord(fAppleCreationTime); // Modification time - - unsigned const timeScale = fCurrentIOState->fQTTimeScale; - size += addWord(timeScale); // Time scale - - unsigned const duration = fCurrentIOState->fQTDurationT; // track units - size += addWord(duration); // Duration - - size += addWord(0x00000000); // Language+Quality -addAtomEnd; - -addAtom(hdlr); - size += addWord(0x00000000); // Version + Flags - size += add4ByteString("mhlr"); // Component type - size += addWord(fCurrentIOState->fQTcomponentSubtype); - // Component subtype - size += add4ByteString("appl"); // Component manufacturer - size += addWord(0x00000000); // Component flags - size += addWord(0x00000000); // Component flags mask - size += addArbitraryString(fCurrentIOState->fQTcomponentName); - // Component name -addAtomEnd; - -addAtom(minf); - SubsessionIOState::atomCreationFunc mediaInformationAtomCreator - = fCurrentIOState->fQTMediaInformationAtomCreator; - size += (this->*mediaInformationAtomCreator)(); - size += addAtom_hdlr2(); - size += addAtom_dinf(); - size += addAtom_stbl(); -addAtomEnd; - -addAtom(smhd); - size += addZeroWords(2); // Version+Flags+Balance+Reserved -addAtomEnd; - -addAtom(vmhd); - size += addWord(0x00000001); // Version + Flags - size += addWord(0x00408000); // Graphics mode + Opcolor[red] - size += addWord(0x80008000); // Opcolor[green} + Opcolor[blue] -addAtomEnd; - -addAtom(gmhd); - size += addAtom_gmin(); -addAtomEnd; - -addAtom(gmin); - size += addWord(0x00000000); // Version + Flags - // The following fields probably aren't used for hint tracks, so just - // use values that I've seen in other files: - size += addWord(0x00408000); // Graphics mode + Opcolor (1st 2 bytes) - size += addWord(0x80008000); // Opcolor (last 4 bytes) - size += addWord(0x00000000); // Balance + Reserved -addAtomEnd; - -unsigned QuickTimeFileSink::addAtom_hdlr2() { - unsigned initFilePosn = ftell(fOutFid); - unsigned size = addAtomHeader("hdlr"); - size += addWord(0x00000000); // Version + Flags - size += add4ByteString("dhlr"); // Component type - size += add4ByteString("alis"); // Component subtype - size += add4ByteString("appl"); // Component manufacturer - size += addZeroWords(2); // Component flags+Component flags mask - size += addArbitraryString("Apple Alias Data Handler"); // Component name -addAtomEnd; - -addAtom(dinf); - size += addAtom_dref(); -addAtomEnd; - -addAtom(dref); - size += addWord(0x00000000); // Version + Flags - size += addWord(0x00000001); // Number of entries - size += addAtom_alis(); -addAtomEnd; - -addAtom(alis); - size += addWord(0x00000001); // Version + Flags -addAtomEnd; - -addAtom(stbl); - size += addAtom_stsd(); - size += addAtom_stts(); - size += addAtom_stsc(); - size += addAtom_stsz(); - size += addAtom_stco(); -addAtomEnd; - -addAtom(stsd); - size += addWord(0x00000000); // Version+Flags - size += addWord(0x00000001); // Number of entries - SubsessionIOState::atomCreationFunc mediaDataAtomCreator - = fCurrentIOState->fQTMediaDataAtomCreator; - size += (this->*mediaDataAtomCreator)(); -addAtomEnd; - -unsigned QuickTimeFileSink::addAtom_genericMedia() { - unsigned initFilePosn = ftell(fOutFid); - - // Our source is assumed to be a "QuickTimeGenericRTPSource" - // Use its "sdAtom" state for our contents: - QuickTimeGenericRTPSource* rtpSource = (QuickTimeGenericRTPSource*) - fCurrentIOState->fOurSubsession.rtpSource(); - QuickTimeGenericRTPSource::QTState& qtState = rtpSource->qtState; - char const* from = qtState.sdAtom; - unsigned size = qtState.sdAtomSize; - for (unsigned i = 0; i < size; ++i) addByte(from[i]); -addAtomEnd; - -unsigned QuickTimeFileSink::addAtom_soundMediaGeneral() { - unsigned initFilePosn = ftell(fOutFid); - unsigned size = addAtomHeader(fCurrentIOState->fQTAudioDataType); - -// General sample description fields: - size += addWord(0x00000000); // Reserved - size += addWord(0x00000001); // Reserved+Data reference index -// Sound sample description fields: - unsigned short const version = fCurrentIOState->fQTSoundSampleVersion; - size += addWord(version<<16); // Version+Revision level - size += addWord(0x00000000); // Vendor - unsigned short numChannels - = (unsigned short)(fCurrentIOState->fOurSubsession.numChannels()); - size += addHalfWord(numChannels); // Number of channels - size += addHalfWord(0x0010); // Sample size - // size += addWord(0x00000000); // Compression ID+Packet size - size += addWord(0xfffe0000); // Compression ID+Packet size ##### - - unsigned const sampleRateFixedPoint = fCurrentIOState->fQTTimeScale << 16; - size += addWord(sampleRateFixedPoint); // Sample rate -addAtomEnd; - -unsigned QuickTimeFileSink::addAtom_Qclp() { - // The beginning of this atom looks just like a general Sound Media atom, - // except with a version field of 1: - unsigned initFilePosn = ftell(fOutFid); - fCurrentIOState->fQTAudioDataType = "Qclp"; - fCurrentIOState->fQTSoundSampleVersion = 1; - unsigned size = addAtom_soundMediaGeneral(); - - // Next, add the four fields that are particular to version 1: - // (Later, parameterize these #####) - size += addWord(0x000000a0); // samples per packet - size += addWord(0x00000000); // ??? - size += addWord(0x00000000); // ??? - size += addWord(0x00000002); // bytes per sample (uncompressed) - - // Other special fields are in a 'wave' atom that follows: - size += addAtom_wave(); -addAtomEnd; - -addAtom(wave); - size += addAtom_frma(); - if (strcmp(fCurrentIOState->fQTAudioDataType, "Qclp") == 0) { - size += addWord(0x00000014); // ??? - size += add4ByteString("Qclp"); // ??? - if (fCurrentIOState->fQTBytesPerFrame == 35) { - size += addAtom_Fclp(); // full-rate QCELP - } else { - size += addAtom_Hclp(); // half-rate QCELP - } // what about other QCELP 'rates'??? ##### - size += addWord(0x00000008); // ??? - size += addWord(0x00000000); // ??? - size += addWord(0x00000000); // ??? - size += addWord(0x00000008); // ??? - } else if (strcmp(fCurrentIOState->fQTAudioDataType, "mp4a") == 0) { - size += addWord(0x0000000c); // ??? - size += add4ByteString("mp4a"); // ??? - size += addWord(0x00000000); // ??? - size += addAtom_esds(); // ESDescriptor - size += addWord(0x00000008); // ??? - size += addWord(0x00000000); // ??? - } -addAtomEnd; - -addAtom(frma); - size += add4ByteString(fCurrentIOState->fQTAudioDataType); // ??? -addAtomEnd; - -addAtom(Fclp); - size += addWord(0x00000000); // ??? -addAtomEnd; - -addAtom(Hclp); - size += addWord(0x00000000); // ??? -addAtomEnd; - -unsigned QuickTimeFileSink::addAtom_mp4a() { - // The beginning of this atom looks just like a general Sound Media atom, - // except with a version field of 1: - unsigned initFilePosn = ftell(fOutFid); - fCurrentIOState->fQTAudioDataType = "mp4a"; - fCurrentIOState->fQTSoundSampleVersion = 1; - unsigned size = addAtom_soundMediaGeneral(); - - if (fGenerateMP4Format) { - size += addAtom_esds(); - } else { - // Next, add the four fields that are particular to version 1: - // (Later, parameterize these #####) - size += addWord(fCurrentIOState->fQTTimeUnitsPerSample); - size += addWord(0x00000001); // ??? - size += addWord(0x00000001); // ??? - size += addWord(0x00000002); // bytes per sample (uncompressed) - - // Other special fields are in a 'wave' atom that follows: - size += addAtom_wave(); - } -addAtomEnd; - -addAtom(esds); - //##### - MediaSubsession& subsession = fCurrentIOState->fOurSubsession; - if (strcmp(subsession.mediumName(), "audio") == 0) { - // MPEG-4 audio - size += addWord(0x00000000); // ??? - size += addWord(0x03808080); // ??? - size += addWord(0x2a000000); // ??? - size += addWord(0x04808080); // ??? - size += addWord(0x1c401500); // ??? - size += addWord(0x18000000); // ??? - size += addWord(0x6d600000); // ??? - size += addWord(0x6d600580); // ??? - size += addByte(0x80); size += addByte(0x80); // ??? - } else if (strcmp(subsession.mediumName(), "video") == 0) { - // MPEG-4 video - size += addWord(0x00000000); // ??? - size += addWord(0x03370000); // ??? - size += addWord(0x1f042f20); // ??? - size += addWord(0x1104fd46); // ??? - size += addWord(0x000d4e10); // ??? - size += addWord(0x000d4e10); // ??? - size += addByte(0x05); // ??? - } - - // Add the source's 'config' information: - unsigned configSize; - unsigned char* config - = parseGeneralConfigStr(subsession.fmtp_config(), configSize); - if (configSize > 0) --configSize; // remove trailing '\0'; - size += addByte(configSize); - for (unsigned i = 0; i < configSize; ++i) { - size += addByte(config[i]); - } - - if (strcmp(subsession.mediumName(), "audio") == 0) { - // MPEG-4 audio - size += addWord(0x06808080); // ??? - size += addByte(0x01); // ??? - } else { - // MPEG-4 video - size += addHalfWord(0x0601); // ??? - size += addByte(0x02); // ??? - } - //##### -addAtomEnd; - -addAtom(srcq); - //##### - size += addWord(0x00000040); // ??? - //##### -addAtomEnd; - -addAtom(h263); -// General sample description fields: - size += addWord(0x00000000); // Reserved - size += addWord(0x00000001); // Reserved+Data reference index -// Video sample description fields: - size += addWord(0x00020001); // Version+Revision level - size += add4ByteString("appl"); // Vendor - size += addWord(0x00000000); // Temporal quality - size += addWord(0x000002fc); // Spatial quality - unsigned const widthAndHeight = (fMovieWidth<<16)|fMovieHeight; - size += addWord(widthAndHeight); // Width+height - size += addWord(0x00480000); // Horizontal resolution - size += addWord(0x00480000); // Vertical resolution - size += addWord(0x00000000); // Data size - size += addWord(0x00010548); // Frame count+Compressor name (start) - // "H.263" - size += addWord(0x2e323633); // Compressor name (continued) - size += addZeroWords(6); // Compressor name (continued - zero) - size += addWord(0x00000018); // Compressor name (final)+Depth - size += addHalfWord(0xffff); // Color table id -addAtomEnd; - -addAtom(mp4v); -// General sample description fields: - size += addWord(0x00000000); // Reserved - size += addWord(0x00000001); // Reserved+Data reference index -// Video sample description fields: - size += addWord(0x00020001); // Version+Revision level - size += add4ByteString("appl"); // Vendor - size += addWord(0x00000200); // Temporal quality - size += addWord(0x00000400); // Spatial quality - unsigned const widthAndHeight = (fMovieWidth<<16)|fMovieHeight; - size += addWord(widthAndHeight); // Width+height - size += addWord(0x00480000); // Horizontal resolution - size += addWord(0x00480000); // Vertical resolution - size += addWord(0x00000000); // Data size - size += addWord(0x00010c4d); // Frame count+Compressor name (start) - // "MPEG-4 Video" - size += addWord(0x5045472d); // Compressor name (continued) - size += addWord(0x34205669); // Compressor name (continued) - size += addWord(0x64656f00); // Compressor name (continued) - size += addZeroWords(4); // Compressor name (continued - zero) - size += addWord(0x00000018); // Compressor name (final)+Depth - size += addHalfWord(0xffff); // Color table id - size += addAtom_esds(); // ESDescriptor - size += addWord(0x00000000); // ??? -addAtomEnd; - -unsigned QuickTimeFileSink::addAtom_rtp() { - unsigned initFilePosn = ftell(fOutFid); - unsigned size = addAtomHeader("rtp "); - - size += addWord(0x00000000); // Reserved (1st 4 bytes) - size += addWord(0x00000001); // Reserved (last 2 bytes) + Data ref index - size += addWord(0x00010001); // Hint track version + Last compat htv - size += addWord(1450); // Max packet size - - size += addAtom_tims(); -addAtomEnd; - -addAtom(tims); - size += addWord(fCurrentIOState->fOurSubsession.rtpTimestampFrequency()); -addAtomEnd; - -addAtom(stts); // Time-to-Sample - size += addWord(0x00000000); // Version+flags - - // First, add a dummy "Number of entries" field - // (and remember its position). We'll fill this field in later: - unsigned numEntriesPosition = ftell(fOutFid); - size += addWord(0); // dummy for "Number of entries" - - // Then, run through the chunk descriptors, and enter the entries - // in this (compressed) Time-to-Sample table: - unsigned numEntries = 0, numSamplesSoFar = 0; - unsigned prevSampleDuration = 0; - unsigned const samplesPerFrame = fCurrentIOState->fQTSamplesPerFrame; - ChunkDescriptor* chunk = fCurrentIOState->fHeadChunk; - while (chunk != NULL) { - unsigned const sampleDuration = chunk->fFrameDuration/samplesPerFrame; - if (sampleDuration != prevSampleDuration) { - // This chunk will start a new table entry, - // so write out the old one (if any): - if (chunk != fCurrentIOState->fHeadChunk) { - ++numEntries; - size += addWord(numSamplesSoFar); // Sample count - size += addWord(prevSampleDuration); // Sample duration - numSamplesSoFar = 0; - } - } - - unsigned const numSamples = chunk->fNumFrames*samplesPerFrame; - numSamplesSoFar += numSamples; - prevSampleDuration = sampleDuration; - chunk = chunk->fNextChunk; - } - - // Then, write out the last entry: - ++numEntries; - size += addWord(numSamplesSoFar); // Sample count - size += addWord(prevSampleDuration); // Sample duration - - // Now go back and fill in the "Number of entries" field: - setWord(numEntriesPosition, numEntries); -addAtomEnd; - -addAtom(stsc); // Sample-to-Chunk - size += addWord(0x00000000); // Version+flags - - // First, add a dummy "Number of entries" field - // (and remember its position). We'll fill this field in later: - unsigned numEntriesPosition = ftell(fOutFid); - size += addWord(0); // dummy for "Number of entries" - - // Then, run through the chunk descriptors, and enter the entries - // in this (compressed) Sample-to-Chunk table: - unsigned numEntries = 0, chunkNumber = 0; - unsigned prevSamplesPerChunk = ~0; - unsigned const samplesPerFrame = fCurrentIOState->fQTSamplesPerFrame; - ChunkDescriptor* chunk = fCurrentIOState->fHeadChunk; - while (chunk != NULL) { - ++chunkNumber; - unsigned const samplesPerChunk = chunk->fNumFrames*samplesPerFrame; - if (samplesPerChunk != prevSamplesPerChunk) { - // This chunk will be a new table entry: - ++numEntries; - size += addWord(chunkNumber); // Chunk number - size += addWord(samplesPerChunk); // Samples per chunk - size += addWord(0x00000001); // Sample description ID - - prevSamplesPerChunk = samplesPerChunk; - } - chunk = chunk->fNextChunk; - } - - // Now go back and fill in the "Number of entries" field: - setWord(numEntriesPosition, numEntries); -addAtomEnd; - -addAtom(stsz); // Sample Size - size += addWord(0x00000000); // Version+flags - - // Begin by checking whether our chunks all have the same - // 'bytes-per-sample'. This determines whether this atom's table - // has just a single entry, or multiple entries. - Boolean haveSingleEntryTable = True; - double firstBPS = 0.0; - ChunkDescriptor* chunk = fCurrentIOState->fHeadChunk; - while (chunk != NULL) { - double bps - = (double)(chunk->fFrameSize)/(fCurrentIOState->fQTSamplesPerFrame); - if (bps < 1.0) { - // I don't think a multiple-entry table would make sense in - // this case, so assume a single entry table ??? ##### - break; - } - - if (firstBPS == 0.0) { - firstBPS = bps; - } else if (bps != firstBPS) { - haveSingleEntryTable = False; - break; - } - - chunk = chunk->fNextChunk; - } - - unsigned sampleSize; - if (haveSingleEntryTable) { - if (fCurrentIOState->isHintTrack() - && fCurrentIOState->fHeadChunk != NULL) { - sampleSize = fCurrentIOState->fHeadChunk->fFrameSize - / fCurrentIOState->fQTSamplesPerFrame; - } else { - // The following doesn't seem right, but seems to do the right thing: - sampleSize = fCurrentIOState->fQTTimeUnitsPerSample; //??? - } - } else { - sampleSize = 0; // indicates a multiple-entry table - } - size += addWord(sampleSize); // Sample size - unsigned const totNumSamples = fCurrentIOState->fQTTotNumSamples; - size += addWord(totNumSamples); // Number of entries - - if (!haveSingleEntryTable) { - // Multiple-entry table: - // Run through the chunk descriptors, entering the sample sizes: - ChunkDescriptor* chunk = fCurrentIOState->fHeadChunk; - while (chunk != NULL) { - unsigned numSamples - = chunk->fNumFrames*(fCurrentIOState->fQTSamplesPerFrame); - unsigned sampleSize - = chunk->fFrameSize/(fCurrentIOState->fQTSamplesPerFrame); - for (unsigned i = 0; i < numSamples; ++i) { - size += addWord(sampleSize); - } - - chunk = chunk->fNextChunk; - } - } -addAtomEnd; - -addAtom(stco); // Chunk Offset - size += addWord(0x00000000); // Version+flags - size += addWord(fCurrentIOState->fNumChunks); // Number of entries - - // Run through the chunk descriptors, entering the file offsets: - ChunkDescriptor* chunk = fCurrentIOState->fHeadChunk; - while (chunk != NULL) { - size += addWord(chunk->fOffsetInFile); - - chunk = chunk->fNextChunk; - } -addAtomEnd; - -addAtom(udta); - size += addAtom_name(); - size += addAtom_hnti(); - size += addAtom_hinf(); -addAtomEnd; - -addAtom(name); - char description[100]; - sprintf(description, "Hinted %s track", - fCurrentIOState->fOurSubsession.mediumName()); - size += addArbitraryString(description, False); // name of object -addAtomEnd; - -addAtom(hnti); - size += addAtom_sdp(); -addAtomEnd; - -unsigned QuickTimeFileSink::addAtom_sdp() { - unsigned initFilePosn = ftell(fOutFid); - unsigned size = addAtomHeader("sdp "); - - // Add this subsession's SDP lines: - char const* sdpLines = fCurrentIOState->fOurSubsession.savedSDPLines(); - // We need to change any "a=control:trackID=" values to be this - // track's actual track id: - char* newSDPLines = new char[strlen(sdpLines)+100/*overkill*/]; - char const* searchStr = "a=control:trackid="; - Boolean foundSearchString = False; - char const *p1, *p2, *p3; - for (p1 = sdpLines; *p1 != '\0'; ++p1) { - for (p2 = p1,p3 = searchStr; tolower(*p2) == *p3; ++p2,++p3) {} - if (*p3 == '\0') { - // We found the end of the search string, at p2. - int beforeTrackNumPosn = p2-sdpLines; - // Look for the subsequent track number, and skip over it: - int trackNumLength; - if (sscanf(p2, " %*d%n", &trackNumLength) < 0) break; - int afterTrackNumPosn = beforeTrackNumPosn + trackNumLength; - - // Replace the old track number with the correct one: - int i; - for (i = 0; i < beforeTrackNumPosn; ++i) newSDPLines[i] = sdpLines[i]; - sprintf(&newSDPLines[i], "%d", fCurrentIOState->fTrackID); - i = afterTrackNumPosn; - int j = i + strlen(&newSDPLines[i]); - while (1) { - if ((newSDPLines[j] = sdpLines[i]) == '\0') break; - ++i; ++j; - } - - foundSearchString = True; - break; - } - } - - if (!foundSearchString) { - // Because we didn't find a "a=control:trackID=" line, - // add one of our own: - sprintf(newSDPLines, "%s%s%d\r\n", - sdpLines, searchStr, fCurrentIOState->fTrackID); - } - - size += addArbitraryString(newSDPLines, False); - delete[] newSDPLines; -addAtomEnd; - -addAtom(hinf); - size += addAtom_totl(); - size += addAtom_npck(); - size += addAtom_tpay(); - size += addAtom_trpy(); - size += addAtom_nump(); - size += addAtom_tpyl(); - // Is 'maxr' required? ##### - size += addAtom_dmed(); - size += addAtom_dimm(); - size += addAtom_drep(); - size += addAtom_tmin(); - size += addAtom_tmax(); - size += addAtom_pmax(); - size += addAtom_dmax(); - size += addAtom_payt(); -addAtomEnd; - -addAtom(totl); - size += addWord(fCurrentIOState->fHINF.trpy.lo); -addAtomEnd; - -addAtom(npck); - size += addWord(fCurrentIOState->fHINF.nump.lo); -addAtomEnd; - -addAtom(tpay); - size += addWord(fCurrentIOState->fHINF.tpyl.lo); -addAtomEnd; - -addAtom(trpy); - size += addWord(fCurrentIOState->fHINF.trpy.hi); - size += addWord(fCurrentIOState->fHINF.trpy.lo); -addAtomEnd; - -addAtom(nump); - size += addWord(fCurrentIOState->fHINF.nump.hi); - size += addWord(fCurrentIOState->fHINF.nump.lo); -addAtomEnd; - -addAtom(tpyl); - size += addWord(fCurrentIOState->fHINF.tpyl.hi); - size += addWord(fCurrentIOState->fHINF.tpyl.lo); -addAtomEnd; - -addAtom(dmed); - size += addWord(fCurrentIOState->fHINF.dmed.hi); - size += addWord(fCurrentIOState->fHINF.dmed.lo); -addAtomEnd; - -addAtom(dimm); - size += addWord(fCurrentIOState->fHINF.dimm.hi); - size += addWord(fCurrentIOState->fHINF.dimm.lo); -addAtomEnd; - -addAtom(drep); - size += addWord(0); - size += addWord(0); -addAtomEnd; - -addAtom(tmin); - size += addWord(0); -addAtomEnd; - -addAtom(tmax); - size += addWord(0); -addAtomEnd; - -addAtom(pmax); - size += addWord(fCurrentIOState->fHINF.pmax); -addAtomEnd; - -addAtom(dmax); - size += addWord(fCurrentIOState->fHINF.dmax); -addAtomEnd; - -addAtom(payt); - MediaSubsession& ourSubsession = fCurrentIOState->fOurSubsession; - RTPSource* rtpSource = ourSubsession.rtpSource(); - size += addByte(rtpSource->rtpPayloadFormat()); - - // Also, add a 'rtpmap' string: / - unsigned rtpmapStringLength = strlen(ourSubsession.codecName()) + 20; - char* rtpmapString = new char[rtpmapStringLength]; - sprintf(rtpmapString, "%s/%d", - ourSubsession.codecName(), rtpSource->timestampFrequency()); - size += addArbitraryString(rtpmapString); - delete[] rtpmapString; -addAtomEnd; - -// A dummy atom (with name "????"): -unsigned QuickTimeFileSink::addAtom_dummy() { - unsigned initFilePosn = ftell(fOutFid); - unsigned size = addAtomHeader("????"); -addAtomEnd; diff --git a/mythtv/libs/libmythlivemedia/liveMedia/QuickTimeGenericRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/QuickTimeGenericRTPSource.cpp deleted file mode 100644 index 2caa1efc7bd..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/QuickTimeGenericRTPSource.cpp +++ /dev/null @@ -1,274 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP Sources containing generic QuickTime stream data, as defined in -// -// Implementation - -#include "QuickTimeGenericRTPSource.hh" - -///// QTGenericBufferedPacket and QTGenericBufferedPacketFactory ///// - -// A subclass of BufferedPacket, used to separate out -// individual frames (when PCK == 2) - -class QTGenericBufferedPacket: public BufferedPacket { -public: - QTGenericBufferedPacket(QuickTimeGenericRTPSource& ourSource); - virtual ~QTGenericBufferedPacket(); - -private: // redefined virtual functions - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); -private: - QuickTimeGenericRTPSource& fOurSource; -}; - -class QTGenericBufferedPacketFactory: public BufferedPacketFactory { -private: // redefined virtual functions - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - - -////////// QuickTimeGenericRTPSource ////////// - -QuickTimeGenericRTPSource* -QuickTimeGenericRTPSource::createNew(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mimeTypeString) { - return new QuickTimeGenericRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, - mimeTypeString); -} - -QuickTimeGenericRTPSource -::QuickTimeGenericRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mimeTypeString) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency, - new QTGenericBufferedPacketFactory), - fMIMEtypeString(strDup(mimeTypeString)) { - qtState.PCK = 0; - qtState.timescale = 0; - qtState.sdAtom = NULL; - qtState.sdAtomSize = qtState.width = qtState.height = 0; -} - -QuickTimeGenericRTPSource::~QuickTimeGenericRTPSource() { - delete[] qtState.sdAtom; - delete[] (char*)fMIMEtypeString; -} - -Boolean QuickTimeGenericRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - unsigned char* headerStart = packet->data(); - unsigned packetSize = packet->dataSize(); - - // The "QuickTime Header" must be at least 4 bytes in size: - // Extract the known fields from the first 4 bytes: - unsigned expectedHeaderSize = 4; - if (packetSize < expectedHeaderSize) return False; - - unsigned char VER = (headerStart[0]&0xF0)>>4; - if (VER > 1) return False; // unknown header version - qtState.PCK = (headerStart[0]&0x0C)>>2; -#ifdef DEBUG - Boolean S = (headerStart[0]&0x02) != 0; -#endif - Boolean Q = (headerStart[0]&0x01) != 0; - - Boolean L = (headerStart[1]&0x80) != 0; - -#ifdef DEBUG - Boolean D = (headerStart[2]&0x80) != 0; - unsigned short payloadId = ((headerStart[2]&0x7F)<<8)|headerStart[3]; -#endif - headerStart += 4; - -#ifdef DEBUG - fprintf(stderr, "PCK: %d, S: %d, Q: %d, L: %d, D: %d, payloadId: %d\n", qtState.PCK, S, Q, L, D, payloadId); -#endif - - if (Q) { // A "QuickTime Payload Description" follows - expectedHeaderSize += 4; - if (packetSize < expectedHeaderSize) return False; - -#ifdef DEBUG - Boolean K = (headerStart[0]&0x80) != 0; - Boolean F = (headerStart[0]&0x40) != 0; - Boolean A = (headerStart[0]&0x20) != 0; - Boolean Z = (headerStart[0]&0x10) != 0; -#endif - unsigned payloadDescriptionLength = (headerStart[2]<<8)|headerStart[3]; - headerStart += 4; - -#ifdef DEBUG - fprintf(stderr, "\tK: %d, F: %d, A: %d, Z: %d, payloadDescriptionLength: %d\n", K, F, A, Z, payloadDescriptionLength); -#endif - // Make sure "payloadDescriptionLength" is valid - if (payloadDescriptionLength < 12) return False; - expectedHeaderSize += (payloadDescriptionLength - 4); - unsigned nonPaddedSize = expectedHeaderSize; - expectedHeaderSize += 3; - expectedHeaderSize -= expectedHeaderSize%4; // adds padding - if (packetSize < expectedHeaderSize) return False; - unsigned char padding = expectedHeaderSize - nonPaddedSize; - -#ifdef DEBUG - unsigned mediaType = (headerStart[0]<<24)|(headerStart[1]<<16) - |(headerStart[2]<<8)|headerStart[3]; -#endif - qtState.timescale = (headerStart[4]<<24)|(headerStart[5]<<16) - |(headerStart[6]<<8)|headerStart[7]; - headerStart += 8; - - payloadDescriptionLength -= 12; -#ifdef DEBUG - fprintf(stderr, "\tmediaType: '%c%c%c%c', timescale: %d, %d bytes of TLVs left\n", mediaType>>24, (mediaType&0xFF0000)>>16, (mediaType&0xFF00)>>8, mediaType&0xFF, qtState.timescale, payloadDescriptionLength); -#endif - - while (payloadDescriptionLength > 3) { - unsigned short tlvLength = (headerStart[0]<<8)|headerStart[1]; - unsigned short tlvType = (headerStart[2]<<8)|headerStart[3]; - payloadDescriptionLength -= 4; - if (tlvLength > payloadDescriptionLength) return False; // bad TLV - headerStart += 4; -#ifdef DEBUG - fprintf(stderr, "\t\tTLV '%c%c', length %d, leaving %d remaining bytes\n", tlvType>>8, tlvType&0xFF, tlvLength, payloadDescriptionLength - tlvLength); - for (int i = 0; i < tlvLength; ++i) fprintf(stderr, "%02x:", headerStart[i]); fprintf(stderr, "\n"); -#endif - - // Check for 'TLV's that we can use for our 'qtState' - switch (tlvType) { - case ('s'<<8|'d'): { // session description atom - // Sanity check: the first 4 bytes of this must equal "tlvLength": - unsigned atomLength = (headerStart[0]<<24)|(headerStart[1]<<16) - |(headerStart[2]<<8)|(headerStart[3]); - if (atomLength != (unsigned)tlvLength) break; - - delete[] qtState.sdAtom; qtState.sdAtom = new char[tlvLength]; - memmove(qtState.sdAtom, headerStart, tlvLength); - qtState.sdAtomSize = tlvLength; - break; - } - case ('t'<<8|'w'): { // track width - qtState.width = (headerStart[0]<<8)|headerStart[1]; - break; - } - case ('t'<<8|'h'): { // track height - qtState.height = (headerStart[0]<<8)|headerStart[1]; - break; - } - } - - payloadDescriptionLength -= tlvLength; - headerStart += tlvLength; - } - if (payloadDescriptionLength > 0) return False; // malformed TLV data - headerStart += padding; - } - - if (L) { // Sample-Specific info follows - expectedHeaderSize += 4; - if (packetSize < expectedHeaderSize) return False; - - unsigned ssInfoLength = (headerStart[2]<<8)|headerStart[3]; - headerStart += 4; - -#ifdef DEBUG - fprintf(stderr, "\tssInfoLength: %d\n", ssInfoLength); -#endif - // Make sure "ssInfoLength" is valid - if (ssInfoLength < 4) return False; - expectedHeaderSize += (ssInfoLength - 4); - unsigned nonPaddedSize = expectedHeaderSize; - expectedHeaderSize += 3; - expectedHeaderSize -= expectedHeaderSize%4; // adds padding - if (packetSize < expectedHeaderSize) return False; - unsigned char padding = expectedHeaderSize - nonPaddedSize; - - ssInfoLength -= 4; - while (ssInfoLength > 3) { - unsigned short tlvLength = (headerStart[0]<<8)|headerStart[1]; -#ifdef DEBUG - unsigned short tlvType = (headerStart[2]<<8)|headerStart[3]; -#endif - ssInfoLength -= 4; - if (tlvLength > ssInfoLength) return False; // bad TLV -#ifdef DEBUG - fprintf(stderr, "\t\tTLV '%c%c', length %d, leaving %d remaining bytes\n", tlvType>>8, tlvType&0xFF, tlvLength, ssInfoLength - tlvLength); - for (int i = 0; i < tlvLength; ++i) fprintf(stderr, "%02x:", headerStart[4+i]); fprintf(stderr, "\n"); -#endif - ssInfoLength -= tlvLength; - headerStart += 4 + tlvLength; - } - if (ssInfoLength > 0) return False; // malformed TLV data - headerStart += padding; - } - - fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame; - // whether the *previous* packet ended a frame - fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); - - resultSpecialHeaderSize = expectedHeaderSize; -#ifdef DEBUG - fprintf(stderr, "Result special header size: %d\n", resultSpecialHeaderSize); -#endif - return True; -} - -char const* QuickTimeGenericRTPSource::MIMEtype() const { - if (fMIMEtypeString == NULL) return MultiFramedRTPSource::MIMEtype(); - - return fMIMEtypeString; -} - - -////////// QTGenericBufferedPacket and QTGenericBufferedPacketFactory impl - -QTGenericBufferedPacket -::QTGenericBufferedPacket(QuickTimeGenericRTPSource& ourSource) - : fOurSource(ourSource) { -} - -QTGenericBufferedPacket::~QTGenericBufferedPacket() { -} - -unsigned QTGenericBufferedPacket:: - nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { - // We use the entire packet for a frame, unless "PCK" == 2 - if (fOurSource.qtState.PCK != 2) return dataSize; - - if (dataSize < 8) return 0; // sanity check - - unsigned short sampleLength = (framePtr[2]<<8)|framePtr[3]; - // later, extract and use the "timestamp" field ##### - framePtr += 8; - dataSize -= 8; - - return sampleLength < dataSize ? sampleLength : dataSize; -} - -BufferedPacket* QTGenericBufferedPacketFactory -::createNewPacket(MultiFramedRTPSource* ourSource) { - return new QTGenericBufferedPacket((QuickTimeGenericRTPSource&)(*ourSource)); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/RTCP.cpp b/mythtv/libs/libmythlivemedia/liveMedia/RTCP.cpp deleted file mode 100644 index eb561724c78..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/RTCP.cpp +++ /dev/null @@ -1,977 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTCP -// Implementation - -#include "RTCP.hh" -#include "GroupsockHelper.hh" -#include "rtcp_from_spec.h" - -////////// RTCPMemberDatabase ////////// - -class RTCPMemberDatabase { -public: - RTCPMemberDatabase(RTCPInstance& ourRTCPInstance) - : fOurRTCPInstance(ourRTCPInstance), fNumMembers(1 /*ourself*/), - fTable(HashTable::create(ONE_WORD_HASH_KEYS)) { - } - - virtual ~RTCPMemberDatabase() { - delete fTable; - } - - Boolean isMember(unsigned ssrc) const { - return fTable->Lookup((char*)(long)ssrc) != NULL; - } - - Boolean noteMembership(unsigned ssrc, unsigned curTimeCount) { - Boolean isNew = !isMember(ssrc); - - if (isNew) { - ++fNumMembers; - } - - // Record the current time, so we can age stale members - fTable->Add((char*)(long)ssrc, (void*)(long)curTimeCount); - - return isNew; - } - - Boolean remove(unsigned ssrc) { - Boolean wasPresent = fTable->Remove((char*)(long)ssrc); - if (wasPresent) { - --fNumMembers; - } - return wasPresent; - } - - unsigned numMembers() const { - return fNumMembers; - } - - void reapOldMembers(unsigned threshold); - -private: - RTCPInstance& fOurRTCPInstance; - unsigned fNumMembers; - HashTable* fTable; -}; - -void RTCPMemberDatabase::reapOldMembers(unsigned threshold) { - Boolean foundOldMember; - unsigned oldSSRC = 0; - - do { - foundOldMember = False; - - HashTable::Iterator* iter - = HashTable::Iterator::create(*fTable); - unsigned long timeCount; - char const* key; - while ((timeCount = (unsigned long)(iter->next(key))) != 0) { -#ifdef DEBUG - fprintf(stderr, "reap: checking SSRC 0x%lx: %ld (threshold %d)\n", (unsigned long)key, timeCount, threshold); -#endif - if (timeCount < (unsigned long)threshold) { // this SSRC is old - unsigned long ssrc = (unsigned long)key; - oldSSRC = (unsigned)ssrc; - foundOldMember = True; - } - } - delete iter; - - if (foundOldMember) { -#ifdef DEBUG - fprintf(stderr, "reap: removing SSRC 0x%x\n", oldSSRC); -#endif - fOurRTCPInstance.removeSSRC(oldSSRC, True); - } - } while (foundOldMember); -} - - -////////// RTCPInstance ////////// - -static double dTimeNow() { - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - return (double) (timeNow.tv_sec + timeNow.tv_usec/1000000.0); -} - -static unsigned const maxPacketSize = 1450; - // bytes (1500, minus some allowance for IP, UDP, UMTP headers) -static unsigned const preferredPacketSize = 1000; // bytes - -RTCPInstance::RTCPInstance(UsageEnvironment& env, Groupsock* RTCPgs, - unsigned totSessionBW, - unsigned char const* cname, - RTPSink* sink, RTPSource const* source, - Boolean isSSMSource) - : Medium(env), fRTCPInterface(this, RTCPgs), fTotSessionBW(totSessionBW), - fSink(sink), fSource(source), fIsSSMSource(isSSMSource), - fCNAME(RTCP_SDES_CNAME, cname), fOutgoingReportCount(1), - fAveRTCPSize(0), fIsInitial(1), fPrevNumMembers(0), - fLastSentSize(0), fLastReceivedSize(0), fLastReceivedSSRC(0), - fTypeOfEvent(EVENT_UNKNOWN), fTypeOfPacket(PACKET_UNKNOWN_TYPE), - fHaveJustSentPacket(False), fLastPacketSentSize(0), - fByeHandlerTask(NULL), fByeHandlerClientData(NULL), - fSRHandlerTask(NULL), fSRHandlerClientData(NULL), - fRRHandlerTask(NULL), fRRHandlerClientData(NULL), - fSpecificRRHandlerTable(NULL) { -#ifdef DEBUG - fprintf(stderr, "RTCPInstance[%p]::RTCPInstance()\n", this); -#endif - if (isSSMSource) RTCPgs->multicastSendOnly(); // don't receive multicast - - double timeNow = dTimeNow(); - fPrevReportTime = fNextReportTime = timeNow; - - fKnownMembers = new RTCPMemberDatabase(*this); - fInBuf = new unsigned char[maxPacketSize]; - if (fKnownMembers == NULL || fInBuf == NULL) return; - - // A hack to save buffer space, because RTCP packets are always small: - unsigned savedMaxSize = OutPacketBuffer::maxSize; - OutPacketBuffer::maxSize = maxPacketSize; - fOutBuf = new OutPacketBuffer(preferredPacketSize, maxPacketSize); - OutPacketBuffer::maxSize = savedMaxSize; - if (fOutBuf == NULL) return; - - // Arrange to handle incoming reports from others: - TaskScheduler::BackgroundHandlerProc* handler - = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; - fRTCPInterface.startNetworkReading(handler); - - // Send our first report. - fTypeOfEvent = EVENT_REPORT; - onExpire(this); -} - -struct RRHandlerRecord { - TaskFunc* rrHandlerTask; - void* rrHandlerClientData; -}; - -RTCPInstance::~RTCPInstance() { -#ifdef DEBUG - fprintf(stderr, "RTCPInstance[%p]::~RTCPInstance()\n", this); -#endif - // Turn off background read handling: - fRTCPInterface.stopNetworkReading(); - - // Begin by sending a BYE. We have to do this immediately, without - // 'reconsideration', because "this" is going away. - fTypeOfEvent = EVENT_BYE; // not used, but... - sendBYE(); - - if (fSpecificRRHandlerTable != NULL) { - AddressPortLookupTable::Iterator iter(*fSpecificRRHandlerTable); - RRHandlerRecord* rrHandler; - while ((rrHandler = (RRHandlerRecord*)iter.next()) != NULL) { - delete rrHandler; - } - delete fSpecificRRHandlerTable; - } - - delete fKnownMembers; - delete fOutBuf; - delete[] fInBuf; -} - -RTCPInstance* RTCPInstance::createNew(UsageEnvironment& env, Groupsock* RTCPgs, - unsigned totSessionBW, - unsigned char const* cname, - RTPSink* sink, RTPSource const* source, - Boolean isSSMSource) { - return new RTCPInstance(env, RTCPgs, totSessionBW, cname, sink, source, - isSSMSource); -} - -Boolean RTCPInstance::lookupByName(UsageEnvironment& env, - char const* instanceName, - RTCPInstance*& resultInstance) { - resultInstance = NULL; // unless we succeed - - Medium* medium; - if (!Medium::lookupByName(env, instanceName, medium)) return False; - - if (!medium->isRTCPInstance()) { - env.setResultMsg(instanceName, " is not a RTCP instance"); - return False; - } - - resultInstance = (RTCPInstance*)medium; - return True; -} - -Boolean RTCPInstance::isRTCPInstance() const { - return True; -} - -unsigned RTCPInstance::numMembers() const { - if (fKnownMembers == NULL) return 0; - - return fKnownMembers->numMembers(); -} - -void RTCPInstance::setByeHandler(TaskFunc* handlerTask, void* clientData, - Boolean handleActiveParticipantsOnly) { - fByeHandlerTask = handlerTask; - fByeHandlerClientData = clientData; - fByeHandleActiveParticipantsOnly = handleActiveParticipantsOnly; -} - -void RTCPInstance::setSRHandler(TaskFunc* handlerTask, void* clientData) { - fSRHandlerTask = handlerTask; - fSRHandlerClientData = clientData; -} - -void RTCPInstance::setRRHandler(TaskFunc* handlerTask, void* clientData) { - fRRHandlerTask = handlerTask; - fRRHandlerClientData = clientData; -} - -void RTCPInstance -::setSpecificRRHandler(netAddressBits fromAddress, Port fromPort, - TaskFunc* handlerTask, void* clientData) { - if (handlerTask == NULL && clientData == NULL) { - unsetSpecificRRHandler(fromAddress, fromPort); - return; - } - - RRHandlerRecord* rrHandler = new RRHandlerRecord; - rrHandler->rrHandlerTask = handlerTask; - rrHandler->rrHandlerClientData = clientData; - if (fSpecificRRHandlerTable == NULL) { - fSpecificRRHandlerTable = new AddressPortLookupTable; - } - fSpecificRRHandlerTable->Add(fromAddress, (~0), fromPort, rrHandler); -} - -void RTCPInstance -::unsetSpecificRRHandler(netAddressBits fromAddress, Port fromPort) { - if (fSpecificRRHandlerTable == NULL) return; - - RRHandlerRecord* rrHandler - = (RRHandlerRecord*)(fSpecificRRHandlerTable->Lookup(fromAddress, (~0), fromPort)); - if (rrHandler != NULL) { - fSpecificRRHandlerTable->Remove(fromAddress, (~0), fromPort); - delete rrHandler; - } -} - -void RTCPInstance::setStreamSocket(int sockNum, - unsigned char streamChannelId) { - // Turn off background read handling: - fRTCPInterface.stopNetworkReading(); - - // Switch to RTCP-over-TCP: - fRTCPInterface.setStreamSocket(sockNum, streamChannelId); - - // Turn background reading back on: - TaskScheduler::BackgroundHandlerProc* handler - = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; - fRTCPInterface.startNetworkReading(handler); -} - -void RTCPInstance::addStreamSocket(int sockNum, - unsigned char streamChannelId) { - // Add the RTCP-over-TCP interface: - fRTCPInterface.setStreamSocket(sockNum, streamChannelId); - - // Turn on background reading for this socket (in case it's not on already): - TaskScheduler::BackgroundHandlerProc* handler - = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler; - fRTCPInterface.startNetworkReading(handler); -} - -static unsigned const IP_UDP_HDR_SIZE = 28; - // overhead (bytes) of IP and UDP hdrs - -#define ADVANCE(n) pkt += (n); packetSize -= (n) - -void RTCPInstance::incomingReportHandler(RTCPInstance* instance, - int /*mask*/) { - instance->incomingReportHandler1(); -} - -void RTCPInstance::incomingReportHandler1() { - unsigned char* pkt = fInBuf; - unsigned packetSize; - struct sockaddr_in fromAddress; - int typeOfPacket = PACKET_UNKNOWN_TYPE; - - do { - if (!fRTCPInterface.handleRead(pkt, maxPacketSize, - packetSize, fromAddress)) { - break; - } - - // Ignore the packet if it was looped-back from ourself: - if (RTCPgs()->wasLoopedBackFromUs(envir(), fromAddress)) { - // However, we still want to handle incoming RTCP packets from - // *other processes* on the same machine. To distinguish this - // case from a true loop-back, check whether we've just sent a - // packet of the same size. (This check isn't perfect, but it seems - // to be the best we can do.) - if (fHaveJustSentPacket && fLastPacketSentSize == packetSize) { - // This is a true loop-back: - fHaveJustSentPacket = False; - break; // ignore this packet - } - } - - if (fIsSSMSource) { - // This packet was received via unicast. 'Reflect' it by resending - // it to the multicast group. - // NOTE: Denial-of-service attacks are possible here. - // Users of this software may wish to add their own, - // application-specific mechanism for 'authenticating' the - // validity of this packet before relecting it. - fRTCPInterface.sendPacket(pkt, packetSize); - fHaveJustSentPacket = True; - fLastPacketSentSize = packetSize; - } - -#ifdef DEBUG - fprintf(stderr, "[%p]saw incoming RTCP packet (from address %s, port %d)\n", this, our_inet_ntoa(fromAddress.sin_addr), ntohs(fromAddress.sin_port)); - unsigned char* p = pkt; - for (unsigned i = 0; i < packetSize; ++i) { - if (i%4 == 0) fprintf(stderr, " "); - fprintf(stderr, "%02x", p[i]); - } - fprintf(stderr, "\n"); -#endif - int totPacketSize = IP_UDP_HDR_SIZE + packetSize; - - // Check the RTCP packet for validity: - // It must at least contain a header (4 bytes), and this header - // must be version=2, with no padding bit, and a payload type of - // SR (200) or RR (201): - if (packetSize < 4) break; - unsigned rtcpHdr = ntohl(*(unsigned*)pkt); - if ((rtcpHdr & 0xE0FE0000) != (0x80000000 | (RTCP_PT_SR<<16))) { -#ifdef DEBUG - fprintf(stderr, "rejected bad RTCP packet: header 0x%08x\n", rtcpHdr); -#endif - break; - } - - // Process each of the individual RTCP 'subpackets' in (what may be) - // a compound RTCP packet. - unsigned reportSenderSSRC = 0; - Boolean packetOK = False; - while (1) { - unsigned rc = (rtcpHdr>>24)&0x1F; - unsigned pt = (rtcpHdr>>16)&0xFF; - unsigned length = 4*(rtcpHdr&0xFFFF); // doesn't count hdr - ADVANCE(4); // skip over the header - if (length > packetSize) break; - - // Assume that each RTCP subpacket begins with a 4-byte SSRC: - if (length < 4) break; length -= 4; - reportSenderSSRC = ntohl(*(unsigned*)pkt); ADVANCE(4); - - Boolean subPacketOK = False; - switch (pt) { - case RTCP_PT_SR: { -#ifdef DEBUG - fprintf(stderr, "SR\n"); -#endif - if (length < 20) break; length -= 20; - - // Extract the NTP timestamp, and note this: - unsigned NTPmsw = ntohl(*(unsigned*)pkt); ADVANCE(4); - unsigned NTPlsw = ntohl(*(unsigned*)pkt); ADVANCE(4); - unsigned rtpTimestamp = ntohl(*(unsigned*)pkt); ADVANCE(4); - if (fSource != NULL) { - RTPReceptionStatsDB& receptionStats - = fSource->receptionStatsDB(); - receptionStats.noteIncomingSR(reportSenderSSRC, - NTPmsw, NTPlsw, rtpTimestamp); - } - ADVANCE(8); // skip over packet count, octet count - - // If a 'SR handler' was set, call it now: - if (fSRHandlerTask != NULL) (*fSRHandlerTask)(fSRHandlerClientData); - - // The rest of the SR is handled like a RR (so, no "break;" here) - } - case RTCP_PT_RR: { -#ifdef DEBUG - fprintf(stderr, "RR\n"); -#endif - unsigned reportBlocksSize = rc*(6*4); - if (length < reportBlocksSize) break; - length -= reportBlocksSize; - - if (fSink != NULL) { - // Use this information to update stats about our transmissions: - RTPTransmissionStatsDB& transmissionStats = fSink->transmissionStatsDB(); - for (unsigned i = 0; i < rc; ++i) { - unsigned senderSSRC = ntohl(*(unsigned*)pkt); ADVANCE(4); - // We care only about reports about our own transmission, not others' - if (senderSSRC == fSink->SSRC()) { - unsigned lossStats = ntohl(*(unsigned*)pkt); ADVANCE(4); - unsigned highestReceived = ntohl(*(unsigned*)pkt); ADVANCE(4); - unsigned jitter = ntohl(*(unsigned*)pkt); ADVANCE(4); - unsigned timeLastSR = ntohl(*(unsigned*)pkt); ADVANCE(4); - unsigned timeSinceLastSR = ntohl(*(unsigned*)pkt); ADVANCE(4); - transmissionStats.noteIncomingRR(reportSenderSSRC, fromAddress, - lossStats, - highestReceived, jitter, - timeLastSR, timeSinceLastSR); - } else { - ADVANCE(4*5); - } - } - } else { - ADVANCE(reportBlocksSize); - } - - if (pt == RTCP_PT_RR) { // i.e., we didn't fall through from 'SR' - // If a 'RR handler' was set, call it now: - - // Specific RR handler: - if (fSpecificRRHandlerTable != NULL) { - netAddressBits fromAddr = fromAddress.sin_addr.s_addr; - Port fromPort(ntohs(fromAddress.sin_port)); - RRHandlerRecord* rrHandler - = (RRHandlerRecord*)(fSpecificRRHandlerTable->Lookup(fromAddr, (~0), fromPort)); - if (rrHandler != NULL) { - if (rrHandler->rrHandlerTask != NULL) { - (*(rrHandler->rrHandlerTask))(rrHandler->rrHandlerClientData); - } - } - } - - // General RR handler: - if (fRRHandlerTask != NULL) (*fRRHandlerTask)(fRRHandlerClientData); - } - - subPacketOK = True; - typeOfPacket = PACKET_RTCP_REPORT; - break; - } - case RTCP_PT_BYE: { -#ifdef DEBUG - fprintf(stderr, "BYE\n"); -#endif - // If a 'BYE handler' was set, call it now: - TaskFunc* byeHandler = fByeHandlerTask; - if (byeHandler != NULL - && (!fByeHandleActiveParticipantsOnly - || (fSource != NULL - && fSource->receptionStatsDB().lookup(reportSenderSSRC) != NULL) - || (fSink != NULL - && fSink->transmissionStatsDB().lookup(reportSenderSSRC) != NULL))) { - fByeHandlerTask = NULL; - // we call this only once by default - (*byeHandler)(fByeHandlerClientData); - } - - // We should really check for & handle >1 SSRCs being present ##### - - subPacketOK = True; - typeOfPacket = PACKET_BYE; - break; - } - // Later handle SDES, APP, and compound RTCP packets ##### - default: -#ifdef DEBUG - fprintf(stderr, "UNSUPPORTED TYPE(0x%x)\n", pt); -#endif - subPacketOK = True; - break; - } - if (!subPacketOK) break; - - // need to check for (& handle) SSRC collision! ##### - -#ifdef DEBUG - fprintf(stderr, "validated RTCP subpacket (type %d): %d, %d, %d, 0x%08x\n", typeOfPacket, rc, pt, length, reportSenderSSRC); -#endif - - // Skip over any remaining bytes in this subpacket: - ADVANCE(length); - - // Check whether another RTCP 'subpacket' follows: - if (packetSize == 0) { - packetOK = True; - break; - } else if (packetSize < 4) { -#ifdef DEBUG - fprintf(stderr, "extraneous %d bytes at end of RTCP packet!\n", packetSize); -#endif - break; - } - rtcpHdr = ntohl(*(unsigned*)pkt); - if ((rtcpHdr & 0xC0000000) != 0x80000000) { -#ifdef DEBUG - fprintf(stderr, "bad RTCP subpacket: header 0x%08x\n", rtcpHdr); -#endif - break; - } - } - - if (!packetOK) { -#ifdef DEBUG - fprintf(stderr, "rejected bad RTCP subpacket: header 0x%08x\n", rtcpHdr); -#endif - break; - } else { -#ifdef DEBUG - fprintf(stderr, "validated entire RTCP packet\n"); -#endif - } - - onReceive(typeOfPacket, totPacketSize, reportSenderSSRC); - } while (0); -} - -void RTCPInstance::onReceive(int typeOfPacket, int totPacketSize, - unsigned ssrc) { - fTypeOfPacket = typeOfPacket; - fLastReceivedSize = totPacketSize; - fLastReceivedSSRC = ssrc; - - int members = (int)numMembers(); - int senders = (fSink != NULL) ? 1 : 0; - - OnReceive(this, // p - this, // e - &members, // members - &fPrevNumMembers, // pmembers - &senders, // senders - &fAveRTCPSize, // avg_rtcp_size - &fPrevReportTime, // tp - dTimeNow(), // tc - fNextReportTime); -} - -void RTCPInstance::sendReport() { -#ifdef DEBUG - fprintf(stderr, "sending REPORT\n"); -#endif - // Begin by including a SR and/or RR report: - addReport(); - - // Then, include a SDES: - addSDES(); - - // Send the report: - sendBuiltPacket(); - - // Periodically clean out old members from our SSRC membership database: - const unsigned membershipReapPeriod = 5; - if ((++fOutgoingReportCount) % membershipReapPeriod == 0) { - unsigned threshold = fOutgoingReportCount - membershipReapPeriod; - fKnownMembers->reapOldMembers(threshold); - } -} - -void RTCPInstance::sendBYE() { -#ifdef DEBUG - fprintf(stderr, "sending BYE\n"); -#endif - // The packet must begin with a SR and/or RR report: - addReport(); - - addBYE(); - sendBuiltPacket(); -} - -void RTCPInstance::sendBuiltPacket() { -#ifdef DEBUG - fprintf(stderr, "sending RTCP packet\n"); - unsigned char* p = fOutBuf->packet(); - for (unsigned i = 0; i < fOutBuf->curPacketSize(); ++i) { - if (i%4 == 0) fprintf(stderr," "); - fprintf(stderr, "%02x", p[i]); - } - fprintf(stderr, "\n"); -#endif - unsigned reportSize = fOutBuf->curPacketSize(); - fRTCPInterface.sendPacket(fOutBuf->packet(), reportSize); - fOutBuf->resetOffset(); - - fLastSentSize = IP_UDP_HDR_SIZE + reportSize; - fHaveJustSentPacket = True; - fLastPacketSentSize = reportSize; -} - -int RTCPInstance::checkNewSSRC() { - return fKnownMembers->noteMembership(fLastReceivedSSRC, - fOutgoingReportCount); -} - -void RTCPInstance::removeLastReceivedSSRC() { - removeSSRC(fLastReceivedSSRC, False/*keep stats around*/); -} - -void RTCPInstance::removeSSRC(u_int32_t ssrc, Boolean alsoRemoveStats) { - fKnownMembers->remove(ssrc); - - if (alsoRemoveStats) { - // Also, remove records of this SSRC from any reception or transmission stats - if (fSource != NULL) fSource->receptionStatsDB().removeRecord(ssrc); - if (fSink != NULL) fSink->transmissionStatsDB().removeRecord(ssrc); - } -} - -void RTCPInstance::onExpire(RTCPInstance* instance) { - instance->onExpire1(); -} - -// Member functions to build specific kinds of report: - -void RTCPInstance::addReport() { - // Include a SR or a RR, depending on whether we - // have an associated sink or source: - if (fSink != NULL) { - addSR(); - } else if (fSource != NULL) { - addRR(); - } -} - -void RTCPInstance::addSR() { - // ASSERT: fSink != NULL - - enqueueCommonReportPrefix(RTCP_PT_SR, fSink->SSRC(), - 5 /* extra words in a SR */); - - // Now, add the 'sender info' for our sink - - // Insert the NTP and RTP timestamps for the 'wallclock time': - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - fOutBuf->enqueueWord(timeNow.tv_sec + 0x83AA7E80); - // NTP timestamp most-significant word (1970 epoch -> 1900 epoch) - double fractionalPart = (timeNow.tv_usec/15625.0)*0x04000000; // 2^32/10^6 - fOutBuf->enqueueWord((unsigned)(fractionalPart+0.5)); - // NTP timestamp least-significant word - unsigned rtpTimestamp = fSink->convertToRTPTimestamp(timeNow); - fOutBuf->enqueueWord(rtpTimestamp); // RTP ts - - // Insert the packet and byte counts: - fOutBuf->enqueueWord(fSink->packetCount()); - fOutBuf->enqueueWord(fSink->octetCount()); - - enqueueCommonReportSuffix(); -} - -void RTCPInstance::addRR() { - // ASSERT: fSource != NULL - - enqueueCommonReportPrefix(RTCP_PT_RR, fSource->SSRC()); - enqueueCommonReportSuffix(); -} - -void RTCPInstance::enqueueCommonReportPrefix(unsigned char packetType, - unsigned SSRC, - unsigned numExtraWords) { - unsigned numReportingSources; - if (fSource == NULL) { - numReportingSources = 0; // we don't receive anything - } else { - RTPReceptionStatsDB& allReceptionStats - = fSource->receptionStatsDB(); - numReportingSources = allReceptionStats.numActiveSourcesSinceLastReset(); - // This must be <32, to fit in 5 bits: - if (numReportingSources >= 32) { numReportingSources = 32; } - // Later: support adding more reports to handle >32 sources (unlikely)##### - } - - unsigned rtcpHdr = 0x80000000; // version 2, no padding - rtcpHdr |= (numReportingSources<<24); - rtcpHdr |= (packetType<<16); - rtcpHdr |= (1 + numExtraWords + 6*numReportingSources); - // each report block is 6 32-bit words long - fOutBuf->enqueueWord(rtcpHdr); - - fOutBuf->enqueueWord(SSRC); -} - -void RTCPInstance::enqueueCommonReportSuffix() { - // Output the report blocks for each source: - if (fSource != NULL) { - RTPReceptionStatsDB& allReceptionStats - = fSource->receptionStatsDB(); - - RTPReceptionStatsDB::Iterator iterator(allReceptionStats); - while (1) { - RTPReceptionStats* receptionStats = iterator.next(); - if (receptionStats == NULL) break; - enqueueReportBlock(receptionStats); - } - - allReceptionStats.reset(); // because we have just generated a report - } -} - -void -RTCPInstance::enqueueReportBlock(RTPReceptionStats* stats) { - fOutBuf->enqueueWord(stats->SSRC()); - - unsigned highestExtSeqNumReceived = stats->highestExtSeqNumReceived(); - - unsigned totNumExpected - = highestExtSeqNumReceived - stats->baseExtSeqNumReceived(); - int totNumLost = totNumExpected - stats->totNumPacketsReceived(); - // 'Clamp' this loss number to a 24-bit signed value: - if (totNumLost > 0x007FFFFF) { - totNumLost = 0x007FFFFF; - } else if (totNumLost < 0) { - if (totNumLost < -0x00800000) totNumLost = 0x00800000; // unlikely, but... - totNumLost &= 0x00FFFFFF; - } - - unsigned numExpectedSinceLastReset - = highestExtSeqNumReceived - stats->lastResetExtSeqNumReceived(); - int numLostSinceLastReset - = numExpectedSinceLastReset - stats->numPacketsReceivedSinceLastReset(); - unsigned char lossFraction; - if (numExpectedSinceLastReset == 0 || numLostSinceLastReset < 0) { - lossFraction = 0; - } else { - lossFraction = (unsigned char) - ((numLostSinceLastReset << 8) / numExpectedSinceLastReset); - } - - fOutBuf->enqueueWord((lossFraction<<24) | totNumLost); - fOutBuf->enqueueWord(highestExtSeqNumReceived); - - fOutBuf->enqueueWord(stats->jitter()); - - unsigned NTPmsw = stats->lastReceivedSR_NTPmsw(); - unsigned NTPlsw = stats->lastReceivedSR_NTPlsw(); - unsigned LSR = ((NTPmsw&0xFFFF)<<16)|(NTPlsw>>16); // middle 32 bits - fOutBuf->enqueueWord(LSR); - - // Figure out how long has elapsed since the last SR rcvd from this src: - struct timeval const& LSRtime = stats->lastReceivedSR_time(); // "last SR" - struct timeval timeNow, timeSinceLSR; - gettimeofday(&timeNow, NULL); - if (timeNow.tv_usec < LSRtime.tv_usec) { - timeNow.tv_usec += 1000000; - timeNow.tv_sec -= 1; - } - timeSinceLSR.tv_sec = timeNow.tv_sec - LSRtime.tv_sec; - timeSinceLSR.tv_usec = timeNow.tv_usec - LSRtime.tv_usec; - // The enqueued time is in units of 1/65536 seconds. - // (Note that 65536/1000000 == 1024/15625) - unsigned DLSR; - if (LSR == 0) { - DLSR = 0; - } else { - DLSR = (timeSinceLSR.tv_sec<<16) - | ( (((timeSinceLSR.tv_usec<<11)+15625)/31250) & 0xFFFF); - } - fOutBuf->enqueueWord(DLSR); -} - -void RTCPInstance::addSDES() { - // For now we support only the CNAME item; later support more ##### - - // Begin by figuring out the size of the entire SDES report: - unsigned numBytes = 4; - // counts the SSRC, but not the header; it'll get subtracted out - numBytes += fCNAME.totalSize(); // includes id and length - numBytes += 1; // the special END item - - unsigned num4ByteWords = (numBytes + 3)/4; - - unsigned rtcpHdr = 0x81000000; // version 2, no padding, 1 SSRC chunk - rtcpHdr |= (RTCP_PT_SDES<<16); - rtcpHdr |= num4ByteWords; - fOutBuf->enqueueWord(rtcpHdr); - - if (fSource != NULL) { - fOutBuf->enqueueWord(fSource->SSRC()); - } else if (fSink != NULL) { - fOutBuf->enqueueWord(fSink->SSRC()); - } - - // Add the CNAME: - fOutBuf->enqueue(fCNAME.data(), fCNAME.totalSize()); - - // Add the 'END' item (i.e., a zero byte), plus any more needed to pad: - unsigned numPaddingBytesNeeded = 4 - (fOutBuf->curPacketSize() % 4); - unsigned char const zero = '\0'; - while (numPaddingBytesNeeded-- > 0) fOutBuf->enqueue(&zero, 1); -} - -void RTCPInstance::addBYE() { - unsigned rtcpHdr = 0x81000000; // version 2, no padding, 1 SSRC - rtcpHdr |= (RTCP_PT_BYE<<16); - rtcpHdr |= 1; // 2 32-bit words total (i.e., with 1 SSRC) - fOutBuf->enqueueWord(rtcpHdr); - - if (fSource != NULL) { - fOutBuf->enqueueWord(fSource->SSRC()); - } else if (fSink != NULL) { - fOutBuf->enqueueWord(fSink->SSRC()); - } -} - -void RTCPInstance::schedule(double nextTime) { - fNextReportTime = nextTime; - - double secondsToDelay = nextTime - dTimeNow(); -#ifdef DEBUG - fprintf(stderr, "schedule(%f->%f)\n", secondsToDelay, nextTime); -#endif - int usToGo = (int)(secondsToDelay * 1000000); - nextTask() = envir().taskScheduler().scheduleDelayedTask(usToGo, - (TaskFunc*)RTCPInstance::onExpire, this); -} - -void RTCPInstance::reschedule(double nextTime) { - envir().taskScheduler().unscheduleDelayedTask(nextTask()); - schedule(nextTime); -} - -void RTCPInstance::onExpire1() { - // Note: fTotSessionBW is kbits per second - double rtcpBW = 0.05*fTotSessionBW*1024/8; // -> bytes per second - - OnExpire(this, // event - numMembers(), // members - (fSink != NULL) ? 1 : 0, // senders - rtcpBW, // rtcp_bw - (fSink != NULL) ? 1 : 0, // we_sent - &fAveRTCPSize, // ave_rtcp_size - &fIsInitial, // initial - dTimeNow(), // tc - &fPrevReportTime, // tp - &fPrevNumMembers // pmembers - ); -} - -////////// SDESItem ////////// - -SDESItem::SDESItem(unsigned char tag, unsigned char const* value) { - unsigned length = strlen((char const*)value); - if (length > 511) length = 511; - - fData[0] = tag; - fData[1] = (unsigned char)length; - memmove(&fData[2], value, length); - - // Pad the trailing bytes to a 4-byte boundary: - while ((length)%4 > 0) fData[2 + length++] = '\0'; -} - -unsigned SDESItem::totalSize() const { - return 2 + (unsigned)fData[1]; -} - - -////////// Implementation of routines imported by the "rtcp_from_spec" C code - -extern "C" void Schedule(double nextTime, event e) { - RTCPInstance* instance = (RTCPInstance*)e; - if (instance == NULL) return; - - instance->schedule(nextTime); -} - -extern "C" void Reschedule(double nextTime, event e) { - RTCPInstance* instance = (RTCPInstance*)e; - if (instance == NULL) return; - - instance->reschedule(nextTime); -} - -extern "C" void SendRTCPReport(event e) { - RTCPInstance* instance = (RTCPInstance*)e; - if (instance == NULL) return; - - instance->sendReport(); -} - -extern "C" void SendBYEPacket(event e) { - RTCPInstance* instance = (RTCPInstance*)e; - if (instance == NULL) return; - - instance->sendBYE(); -} - -extern "C" int TypeOfEvent(event e) { - RTCPInstance* instance = (RTCPInstance*)e; - if (instance == NULL) return EVENT_UNKNOWN; - - return instance->typeOfEvent(); -} - -extern "C" int SentPacketSize(event e) { - RTCPInstance* instance = (RTCPInstance*)e; - if (instance == NULL) return 0; - - return instance->sentPacketSize(); -} - -extern "C" int PacketType(packet p) { - RTCPInstance* instance = (RTCPInstance*)p; - if (instance == NULL) return PACKET_UNKNOWN_TYPE; - - return instance->packetType(); -} - -extern "C" int ReceivedPacketSize(packet p) { - RTCPInstance* instance = (RTCPInstance*)p; - if (instance == NULL) return 0; - - return instance->receivedPacketSize(); -} - -extern "C" int NewMember(packet p) { - RTCPInstance* instance = (RTCPInstance*)p; - if (instance == NULL) return 0; - - return instance->checkNewSSRC(); -} - -extern "C" int NewSender(packet /*p*/) { - return 0; // we don't yet recognize senders other than ourselves ##### -} - -extern "C" void AddMember(packet /*p*/) { - // Do nothing; all of the real work was done when NewMember() was called -} - -extern "C" void AddSender(packet /*p*/) { - // we don't yet recognize senders other than ourselves ##### -} - -extern "C" void RemoveMember(packet p) { - RTCPInstance* instance = (RTCPInstance*)p; - if (instance == NULL) return; - - instance->removeLastReceivedSSRC(); -} - -extern "C" void RemoveSender(packet /*p*/) { - // we don't yet recognize senders other than ourselves ##### -} - -extern "C" double drand30() { - unsigned tmp = our_random()&0x3FFFFFFF; // a random 30-bit integer - return tmp/(double)(1024*1024*1024); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/RTPInterface.cpp b/mythtv/libs/libmythlivemedia/liveMedia/RTPInterface.cpp deleted file mode 100644 index 625771e26cf..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/RTPInterface.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// An abstraction of a network interface used for RTP (or RTCP). -// (This allows the RTP-over-TCP hack (RFC 2326, section 10.12) to -// be implemented transparently.) -// Implementation - -#include "RTPInterface.hh" -#include -#include - -////////// Helper Functions - Definition ////////// - -// Helper routines and data structures, used to implement -// sending/receiving RTP/RTCP over a TCP socket: - -static void sendRTPOverTCP(unsigned char* packet, unsigned packetSize, - int socketNum, unsigned char streamChannelId); - -// Reading RTP-over-TCP is implemented using two levels of hash tables. -// The top-level hash table maps TCP socket numbers to a -// "SocketDescriptor" that contains a hash table for each of the -// sub-channels that are reading from this socket. - -static HashTable* socketHashTable(UsageEnvironment& env) { - _Tables* ourTables = _Tables::getOurTables(env); - if (ourTables->socketTable == NULL) { - // Create a new socket number -> SocketDescriptor mapping table: - ourTables->socketTable = HashTable::create(ONE_WORD_HASH_KEYS); - } - return (HashTable*)(ourTables->socketTable); -} - -class SocketDescriptor { -public: - SocketDescriptor(UsageEnvironment& env, int socketNum); - virtual ~SocketDescriptor(); - - void registerRTPInterface(unsigned char streamChannelId, - RTPInterface* rtpInterface); - RTPInterface* lookupRTPInterface(unsigned char streamChannelId); - void deregisterRTPInterface(unsigned char streamChannelId); - -private: - static void tcpReadHandler(SocketDescriptor*, int mask); - -private: - UsageEnvironment& fEnv; - int fOurSocketNum; - HashTable* fSubChannelHashTable; -}; - -static SocketDescriptor* lookupSocketDescriptor(UsageEnvironment& env, - int sockNum) { - char const* key = (char const*)(long)sockNum; - return (SocketDescriptor*)(socketHashTable(env)->Lookup(key)); -} - -static void removeSocketDescription(UsageEnvironment& env, int sockNum) { - char const* key = (char const*)(long)sockNum; - HashTable* table = socketHashTable(env); - table->Remove(key); - - if (table->IsEmpty()) { - // We can also delete the table (to reclaim space): - _Tables* ourTables = _Tables::getOurTables(env); - delete table; - ourTables->socketTable = NULL; - ourTables->reclaimIfPossible(); - } -} - - -////////// RTPInterface - Implementation ////////// - -RTPInterface::RTPInterface(Medium* owner, Groupsock* gs) - : fOwner(owner), fGS(gs), - fTCPStreams(NULL), - fNextTCPReadSize(0), fNextTCPReadStreamSocketNum(-1), - fReadHandlerProc(NULL), - fAuxReadHandlerFunc(NULL), fAuxReadHandlerClientData(NULL) { -} - -RTPInterface::~RTPInterface() { - delete fTCPStreams; -} - -Boolean RTPOverTCP_OK = True; // HACK: For detecting TCP socket failure externally ##### - -void RTPInterface::setStreamSocket(int sockNum, - unsigned char streamChannelId) { - fGS->removeAllDestinations(); - addStreamSocket(sockNum, streamChannelId); -} - -void RTPInterface::addStreamSocket(int sockNum, - unsigned char streamChannelId) { - if (sockNum < 0) return; - else RTPOverTCP_OK = True; //##### HACK - - for (tcpStreamRecord* streams = fTCPStreams; streams != NULL; - streams = streams->fNext) { - if (streams->fStreamSocketNum == sockNum - && streams->fStreamChannelId == streamChannelId) { - return; // we already have it - } - } - - fTCPStreams = new tcpStreamRecord(sockNum, streamChannelId, fTCPStreams); -} - -void RTPInterface::removeStreamSocket(int sockNum, - unsigned char streamChannelId) { - for (tcpStreamRecord** streamsPtr = &fTCPStreams; *streamsPtr != NULL; - streamsPtr = &((*streamsPtr)->fNext)) { - if ((*streamsPtr)->fStreamSocketNum == sockNum - && (*streamsPtr)->fStreamChannelId == streamChannelId) { - // Remove the record pointed to by *streamsPtr : - tcpStreamRecord* next = (*streamsPtr)->fNext; - (*streamsPtr)->fNext = NULL; - delete (*streamsPtr); - *streamsPtr = next; - return; - } - } -} - -void RTPInterface::sendPacket(unsigned char* packet, unsigned packetSize) { - // Normal case: Send as a UDP packet: - fGS->output(envir(), fGS->ttl(), packet, packetSize); - - // Also, send over each of our TCP socket: - for (tcpStreamRecord* streams = fTCPStreams; streams != NULL; - streams = streams->fNext) { - sendRTPOverTCP(packet, packetSize, - streams->fStreamSocketNum, streams->fStreamChannelId); - } -} - -void RTPInterface -::startNetworkReading(TaskScheduler::BackgroundHandlerProc* handlerProc) { - // Normal case: Arrange to read UDP packets: - envir().taskScheduler(). - turnOnBackgroundReadHandling(fGS->socketNum(), handlerProc, fOwner); - - // Also, receive RTP over TCP, on each of our TCP connections: - fReadHandlerProc = handlerProc; - for (tcpStreamRecord* streams = fTCPStreams; streams != NULL; - streams = streams->fNext) { - // Get a socket descriptor for "streams->fStreamSocketNum": - SocketDescriptor* socketDescriptor - = lookupSocketDescriptor(envir(), streams->fStreamSocketNum); - if (socketDescriptor == NULL) { - socketDescriptor - = new SocketDescriptor(envir(), streams->fStreamSocketNum); - socketHashTable(envir())->Add((char const*)(long)(streams->fStreamSocketNum), - socketDescriptor); - } - - // Tell it about our subChannel: - socketDescriptor->registerRTPInterface(streams->fStreamChannelId, this); - } -} - -Boolean RTPInterface::handleRead(unsigned char* buffer, - unsigned bufferMaxSize, - unsigned& bytesRead, - struct sockaddr_in& fromAddress) { - Boolean readSuccess; - if (fNextTCPReadStreamSocketNum < 0) { - // Normal case: read from the (datagram) 'groupsock': - readSuccess = fGS->handleRead(buffer, bufferMaxSize, bytesRead, fromAddress); - } else { - // Read from the TCP connection: - bytesRead = 0; - unsigned totBytesToRead = fNextTCPReadSize; - if (totBytesToRead > bufferMaxSize) totBytesToRead = bufferMaxSize; - unsigned curBytesToRead = totBytesToRead; - unsigned curBytesRead; - while ((curBytesRead = readSocket(envir(), fNextTCPReadStreamSocketNum, - &buffer[bytesRead], curBytesToRead, - fromAddress)) > 0) { - bytesRead += curBytesRead; - if (bytesRead >= totBytesToRead) break; - curBytesToRead -= curBytesRead; - } - if (curBytesRead <= 0) { - bytesRead = 0; - readSuccess = False; - RTPOverTCP_OK = False; // HACK ##### - } else { - readSuccess = True; - } - fNextTCPReadStreamSocketNum = -1; // default, for next time - } - - if (readSuccess && fAuxReadHandlerFunc != NULL) { - // Also pass the newly-read packet data to our auxilliary handler: - (*fAuxReadHandlerFunc)(fAuxReadHandlerClientData, buffer, bytesRead); - } - return readSuccess; -} - -void RTPInterface::stopNetworkReading() { - // Normal case - envir().taskScheduler().turnOffBackgroundReadHandling(fGS->socketNum()); - - // Also turn off read handling on each of our TCP connections: - for (tcpStreamRecord* streams = fTCPStreams; streams != NULL; - streams = streams->fNext) { - SocketDescriptor* socketDescriptor - = lookupSocketDescriptor(envir(), streams->fStreamSocketNum); - if (socketDescriptor != NULL) { - socketDescriptor->deregisterRTPInterface(streams->fStreamChannelId); - // Note: This may delete "socketDescriptor", - // if no more interfaces are using this socket - } - } -} - - -////////// Helper Functions - Implementation ///////// - -void sendRTPOverTCP(unsigned char* packet, unsigned packetSize, - int socketNum, unsigned char streamChannelId) { -#ifdef DEBUG - fprintf(stderr, "sendRTPOverTCP: %d bytes over channel %d (socket %d)\n", - packetSize, streamChannelId, socketNum); fflush(stderr); -#endif - // Send RTP over TCP, using the encoding defined in - // RFC 2326, section 10.12: - do { - char const dollar = '$'; - if (send(socketNum, &dollar, 1, 0) != 1) break; - if (send(socketNum, (char*)&streamChannelId, 1, 0) != 1) break; - - char netPacketSize[2]; - netPacketSize[0] = (char) ((packetSize&0xFF00)>>8); - netPacketSize[1] = (char) (packetSize&0xFF); - if (send(socketNum, netPacketSize, 2, 0) != 2) break; - - if (send(socketNum, (char*)packet, packetSize, 0) != (int)packetSize) break; - -#ifdef DEBUG - fprintf(stderr, "sendRTPOverTCP: completed\n"); fflush(stderr); -#endif - - return; - } while (0); - - RTPOverTCP_OK = False; // HACK ##### -#ifdef DEBUG - fprintf(stderr, "sendRTPOverTCP: failed!\n"); fflush(stderr); -#endif -} - -SocketDescriptor::SocketDescriptor(UsageEnvironment& env, int socketNum) - : fEnv(env), fOurSocketNum(socketNum), - fSubChannelHashTable(HashTable::create(ONE_WORD_HASH_KEYS)) { -} - -SocketDescriptor::~SocketDescriptor() { - delete fSubChannelHashTable; -} - -void SocketDescriptor::registerRTPInterface(unsigned char streamChannelId, - RTPInterface* rtpInterface) { - Boolean isFirstRegistration = fSubChannelHashTable->IsEmpty(); - fSubChannelHashTable->Add((char const*)(long)streamChannelId, - rtpInterface); - - if (isFirstRegistration) { - // Arrange to handle reads on this TCP socket: - TaskScheduler::BackgroundHandlerProc* handler - = (TaskScheduler::BackgroundHandlerProc*)&tcpReadHandler; - fEnv.taskScheduler(). - turnOnBackgroundReadHandling(fOurSocketNum, handler, this); - } -} - -RTPInterface* SocketDescriptor -::lookupRTPInterface(unsigned char streamChannelId) { - char const* lookupArg = (char const*)(long)streamChannelId; - return (RTPInterface*)(fSubChannelHashTable->Lookup(lookupArg)); -} - -void SocketDescriptor -::deregisterRTPInterface(unsigned char streamChannelId) { - fSubChannelHashTable->Remove((char const*)(long)streamChannelId); - - if (fSubChannelHashTable->IsEmpty()) { - // No more interfaces are using us, so it's curtains for us now - fEnv.taskScheduler().turnOffBackgroundReadHandling(fOurSocketNum); - removeSocketDescription(fEnv, fOurSocketNum); - delete this; - } -} - -void SocketDescriptor::tcpReadHandler(SocketDescriptor* socketDescriptor, - int mask) { - do { - UsageEnvironment& env = socketDescriptor->fEnv; // abbrev - int socketNum = socketDescriptor->fOurSocketNum; - - // Begin by reading and discarding any characters that aren't '$'. - // Any such characters are probably regular RTSP responses or - // commands from the server. At present, we can't do anything with - // these, because we have taken complete control of reading this socket. - // (Later, fix) ##### - unsigned char c; - struct sockaddr_in fromAddress; - do { - if (readSocket(env, socketNum, &c, 1, fromAddress) != 1) { // error reading TCP socket - env.taskScheduler().turnOffBackgroundReadHandling(socketNum); // stops further calls to us - return; - } - } while (c != '$'); - - // The next byte is the stream channel id: - unsigned char streamChannelId; - if (readSocket(env, socketNum, &streamChannelId, 1, fromAddress) - != 1) break; - RTPInterface* rtpInterface - = socketDescriptor->lookupRTPInterface(streamChannelId); - if (rtpInterface == NULL) break; // we're not interested in this channel - - // The next two bytes are the RTP or RTCP packet size (in network order) - unsigned short size; - if (readSocketExact(env, socketNum, (unsigned char*)&size, 2, - fromAddress) != 2) break; - rtpInterface->fNextTCPReadSize = ntohs(size); - rtpInterface->fNextTCPReadStreamSocketNum = socketNum; -#ifdef DEBUG - fprintf(stderr, "SocketDescriptor::tcpReadHandler() reading %d bytes on channel %d\n", rtpInterface->fNextTCPReadSize, streamChannelId); -#endif - - // Now that we have the data set up, call this subchannel's - // read handler: - if (rtpInterface->fReadHandlerProc != NULL) { - rtpInterface->fReadHandlerProc(rtpInterface->fOwner, mask); - } - - } while (0); -} - - -////////// tcpStreamRecord implementation ////////// - -tcpStreamRecord -::tcpStreamRecord(int streamSocketNum, unsigned char streamChannelId, - tcpStreamRecord* next) - : fNext(next), - fStreamSocketNum(streamSocketNum), fStreamChannelId(streamChannelId) { -} - -tcpStreamRecord::~tcpStreamRecord() { - delete fNext; -} - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/RTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/RTPSink.cpp deleted file mode 100644 index 38c8cc5a0b3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/RTPSink.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP Sinks -// Implementation - -#include "RTPSink.hh" -#include "GroupsockHelper.hh" - -////////// RTPSink ////////// - -Boolean RTPSink::lookupByName(UsageEnvironment& env, char const* sinkName, - RTPSink*& resultSink) { - resultSink = NULL; // unless we succeed - - MediaSink* sink; - if (!MediaSink::lookupByName(env, sinkName, sink)) return False; - - if (!sink->isRTPSink()) { - env.setResultMsg(sinkName, " is not a RTP sink"); - return False; - } - - resultSink = (RTPSink*)sink; - return True; -} - -Boolean RTPSink::isRTPSink() const { - return True; -} - -RTPSink::RTPSink(UsageEnvironment& env, - Groupsock* rtpGS, unsigned char rtpPayloadType, - unsigned rtpTimestampFrequency, - char const* rtpPayloadFormatName, - unsigned numChannels) - : MediaSink(env), fRTPInterface(this, rtpGS), - fRTPPayloadType(rtpPayloadType), - fPacketCount(0), fOctetCount(0), fTotalOctetCount(0), - fTimestampFrequency(rtpTimestampFrequency), fHaveComputedFirstTimestamp(False), - fNumChannels(numChannels) { - fRTPPayloadFormatName - = strDup(rtpPayloadFormatName == NULL ? "???" : rtpPayloadFormatName); - gettimeofday(&fCreationTime, NULL); - fTotalOctetCountStartTime = fCreationTime; - - fSeqNo = (u_int16_t)our_random(); - fSSRC = our_random32(); - fTimestampBase = our_random32(); - fCurrentTimestamp = fTimestampBase; - - fTransmissionStatsDB = new RTPTransmissionStatsDB(*this); -} - -RTPSink::~RTPSink() { - delete fTransmissionStatsDB; - delete[] (char*)fRTPPayloadFormatName; -} - -u_int32_t RTPSink::convertToRTPTimestamp(struct timeval tv) { - u_int32_t rtpTimestampIncrement = timevalToTimestamp(tv); - - if (!fHaveComputedFirstTimestamp) { - // Make the first timestamp the same as the current "fTimestampBase", so that - // timestamps begin with the value we promised when this "RTPSink" was created: - fTimestampBase -= rtpTimestampIncrement; - fHaveComputedFirstTimestamp = True; - } - - u_int32_t const rtpTimestamp = fTimestampBase + rtpTimestampIncrement; -#ifdef DEBUG_TIMESTAMPS - fprintf(stderr, "fTimestampBase: 0x%08x, tv: %lu.%06ld\n\t=> RTP timestamp: 0x%08x\n", - fTimestampBase, tv.tv_sec, tv.tv_usec, rtpTimestamp); - fflush(stderr); -#endif - - return rtpTimestamp; -} - -u_int32_t RTPSink::timevalToTimestamp(struct timeval tv) const { - u_int32_t timestamp = (fTimestampFrequency*tv.tv_sec); - timestamp += (u_int32_t)((2.0*fTimestampFrequency*tv.tv_usec + 1000000.0)/2000000); - // note: rounding - return timestamp; -} - -void RTPSink::getTotalBitrate(unsigned& outNumBytes, double& outElapsedTime) { - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - - outNumBytes = fTotalOctetCount; - outElapsedTime = (double)(timeNow.tv_sec-fTotalOctetCountStartTime.tv_sec) - + (timeNow.tv_usec-fTotalOctetCountStartTime.tv_usec)/1000000.0; - - fTotalOctetCount = 0; - fTotalOctetCountStartTime = timeNow; -} - -char const* RTPSink::sdpMediaType() const { - return "data"; - // default SDP media (m=) type, unless redefined by subclasses -} - -char* RTPSink::rtpmapLine() const { - if (rtpPayloadType() >= 96) { // the payload format type is dynamic - char* encodingParamsPart; - if (numChannels() != 1) { - encodingParamsPart = new char[1 + 20 /* max int len */]; - sprintf(encodingParamsPart, "/%d", numChannels()); - } else { - encodingParamsPart = strDup(""); - } - char const* const rtpmapFmt = "a=rtpmap:%d %s/%d%s\r\n"; - unsigned rtpmapFmtSize = strlen(rtpmapFmt) - + 3 /* max char len */ + strlen(rtpPayloadFormatName()) - + 20 /* max int len */ + strlen(encodingParamsPart); - char* rtpmapLine = new char[rtpmapFmtSize]; - sprintf(rtpmapLine, rtpmapFmt, - rtpPayloadType(), rtpPayloadFormatName(), - rtpTimestampFrequency(), encodingParamsPart); - delete[] encodingParamsPart; - - return rtpmapLine; - } else { - // The payload format is staic, so there's no "a=rtpmap:" line: - return strDup(""); - } -} - -char const* RTPSink::auxSDPLine() { - return NULL; // by default -} - - -////////// RTPTransmissionStatsDB ////////// - -RTPTransmissionStatsDB::RTPTransmissionStatsDB(RTPSink& rtpSink) - : fOurRTPSink(rtpSink), - fTable(HashTable::create(ONE_WORD_HASH_KEYS)) { - fNumReceivers=0; -} - -RTPTransmissionStatsDB::~RTPTransmissionStatsDB() { - // First, remove and delete all stats records from the table: - RTPTransmissionStats* stats; - while ((stats = (RTPTransmissionStats*)fTable->RemoveNext()) != NULL) { - delete stats; - } - - // Then, delete the table itself: - delete fTable; -} - -void RTPTransmissionStatsDB -::noteIncomingRR(u_int32_t SSRC, struct sockaddr_in const& lastFromAddress, - unsigned lossStats, unsigned lastPacketNumReceived, - unsigned jitter, unsigned lastSRTime, unsigned diffSR_RRTime) { - RTPTransmissionStats* stats = lookup(SSRC); - if (stats == NULL) { - // This is the first time we've heard of this SSRC. - // Create a new record for it: - stats = new RTPTransmissionStats(fOurRTPSink, SSRC); - if (stats == NULL) return; - add(SSRC, stats); -#ifdef DEBUG_RR - fprintf(stderr, "Adding new entry for SSRC %x in RTPTransmissionStatsDB\n", SSRC); -#endif - } - - stats->noteIncomingRR(lastFromAddress, - lossStats, lastPacketNumReceived, jitter, - lastSRTime, diffSR_RRTime); -} - -void RTPTransmissionStatsDB::removeRecord(u_int32_t SSRC) { - RTPTransmissionStats* stats = lookup(SSRC); - if (stats != NULL) { - long SSRC_long = (long)SSRC; - fTable->Remove((char const*)SSRC_long); - --fNumReceivers; - delete stats; - } -} - -RTPTransmissionStatsDB::Iterator -::Iterator(RTPTransmissionStatsDB& receptionStatsDB) - : fIter(HashTable::Iterator::create(*(receptionStatsDB.fTable))) { -} - -RTPTransmissionStatsDB::Iterator::~Iterator() { - delete fIter; -} - -RTPTransmissionStats* -RTPTransmissionStatsDB::Iterator::next() { - char const* key; // dummy - - return (RTPTransmissionStats*)(fIter->next(key)); -} - -RTPTransmissionStats* RTPTransmissionStatsDB::lookup(u_int32_t SSRC) const { - long SSRC_long = (long)SSRC; - return (RTPTransmissionStats*)(fTable->Lookup((char const*)SSRC_long)); -} - -void RTPTransmissionStatsDB::add(u_int32_t SSRC, RTPTransmissionStats* stats) { - long SSRC_long = (long)SSRC; - fTable->Add((char const*)SSRC_long, stats); - ++fNumReceivers; -} - - -////////// RTPTransmissionStats ////////// - -RTPTransmissionStats::RTPTransmissionStats(RTPSink& rtpSink, u_int32_t SSRC) - : fOurRTPSink(rtpSink), fSSRC(SSRC), fLastPacketNumReceived(0), - fPacketLossRatio(0), fTotNumPacketsLost(0), fJitter(0), - fLastSRTime(0), fDiffSR_RRTime(0), fFirstPacket(True), - fTotalOctetCount_hi(0), fTotalOctetCount_lo(0), - fTotalPacketCount_hi(0), fTotalPacketCount_lo(0) { - gettimeofday(&fTimeCreated, NULL); - - fLastOctetCount = rtpSink.octetCount(); - fLastPacketCount = rtpSink.packetCount(); -} - -RTPTransmissionStats::~RTPTransmissionStats() {} - -void RTPTransmissionStats -::noteIncomingRR(struct sockaddr_in const& lastFromAddress, - unsigned lossStats, unsigned lastPacketNumReceived, - unsigned jitter, unsigned lastSRTime, - unsigned diffSR_RRTime) { - if (fFirstPacket) { - fFirstPacket = False; - fFirstPacketNumReported = lastPacketNumReceived; - } else { - fOldValid = True; - fOldLastPacketNumReceived = fLastPacketNumReceived; - fOldTotNumPacketsLost = fTotNumPacketsLost; - } - gettimeofday(&fTimeReceived, NULL); - - fLastFromAddress = lastFromAddress; - fPacketLossRatio = lossStats>>24; - fTotNumPacketsLost = lossStats&0xFFFFFF; - fLastPacketNumReceived = lastPacketNumReceived; - fJitter = jitter; - fLastSRTime = lastSRTime; - fDiffSR_RRTime = diffSR_RRTime; -#ifdef DEBUG_RR - fprintf(stderr, "RTCP RR data (received at %lu.%06ld): lossStats 0x%08x, lastPacketNumReceived 0x%08x, jitter 0x%08x, lastSRTime 0x%08x, diffSR_RRTime 0x%08x\n", - fTimeReceived.tv_sec, fTimeReceived.tv_usec, lossStats, lastPacketNumReceived, jitter, lastSRTime, diffSR_RRTime); - unsigned rtd = roundTripDelay(); - fprintf(stderr, "=> round-trip delay: 0x%04x (== %f seconds)\n", rtd, rtd/65536.0); -#endif - - // Update our counts of the total number of octets and packets sent towards - // this receiver: - u_int32_t newOctetCount = fOurRTPSink.octetCount(); - u_int32_t octetCountDiff = newOctetCount - fLastOctetCount; - fLastOctetCount = newOctetCount; - u_int32_t prevTotalOctetCount_lo = fTotalOctetCount_lo; - fTotalOctetCount_lo += octetCountDiff; - if (fTotalOctetCount_lo < prevTotalOctetCount_lo) { // wrap around - ++fTotalOctetCount_hi; - } - - u_int32_t newPacketCount = fOurRTPSink.packetCount(); - u_int32_t packetCountDiff = newPacketCount - fLastPacketCount; - fLastPacketCount = newPacketCount; - u_int32_t prevTotalPacketCount_lo = fTotalPacketCount_lo; - fTotalPacketCount_lo += packetCountDiff; - if (fTotalPacketCount_lo < prevTotalPacketCount_lo) { // wrap around - ++fTotalPacketCount_hi; - } -} - -unsigned RTPTransmissionStats::roundTripDelay() const { - // Compute the round-trip delay that was indicated by the most recently-received - // RTCP RR packet. Use the method noted in the RTP/RTCP specification (RFC 3350). - - if (fLastSRTime == 0) { - // Either no RTCP RR packet has been received yet, or else the - // reporting receiver has not yet received any RTCP SR packets from us: - return 0; - } - - // First, convert the time that we received the last RTCP RR packet to NTP format, - // in units of 1/65536 (2^-16) seconds: - unsigned lastReceivedTimeNTP_high - = fTimeReceived.tv_sec + 0x83AA7E80; // 1970 epoch -> 1900 epoch - double fractionalPart = (fTimeReceived.tv_usec*0x0400)/15625.0; // 2^16/10^6 - unsigned lastReceivedTimeNTP - = (unsigned)((lastReceivedTimeNTP_high<<16) + fractionalPart + 0.5); - - int rawResult = lastReceivedTimeNTP - fLastSRTime - fDiffSR_RRTime; - if (rawResult < 0) { - // This can happen if there's clock drift between the sender and receiver, - // and if the round-trip time was very small. - rawResult = 0; - } - return (unsigned)rawResult; -} - -void RTPTransmissionStats::getTotalOctetCount(u_int32_t& hi, u_int32_t& lo) { - hi = fTotalOctetCount_hi; - lo = fTotalOctetCount_lo; -} - -void RTPTransmissionStats::getTotalPacketCount(u_int32_t& hi, u_int32_t& lo) { - hi = fTotalPacketCount_hi; - lo = fTotalPacketCount_lo; -} - -unsigned RTPTransmissionStats::packetsReceivedSinceLastRR() const { - if (!fOldValid) return 0; - - return fLastPacketNumReceived-fOldLastPacketNumReceived; -} - -int RTPTransmissionStats::packetsLostBetweenRR() const { - if (!fOldValid) return 0; - - return fTotNumPacketsLost - fOldTotNumPacketsLost; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/RTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/RTPSource.cpp deleted file mode 100644 index dcf2b515200..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/RTPSource.cpp +++ /dev/null @@ -1,396 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP Sources -// Implementation - -#include "RTPSource.hh" -#include "GroupsockHelper.hh" - -////////// RTPSource ////////// - -Boolean RTPSource::lookupByName(UsageEnvironment& env, - char const* sourceName, - RTPSource*& resultSource) { - resultSource = NULL; // unless we succeed - - MediaSource* source; - if (!MediaSource::lookupByName(env, sourceName, source)) return False; - - if (!source->isRTPSource()) { - env.setResultMsg(sourceName, " is not a RTP source"); - return False; - } - - resultSource = (RTPSource*)source; - return True; -} - -Boolean RTPSource::hasBeenSynchronizedUsingRTCP() { - return fCurPacketHasBeenSynchronizedUsingRTCP; -} - -Boolean RTPSource::isRTPSource() const { - return True; -} - -RTPSource::RTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency) - : FramedSource(env), - fRTPInterface(this, RTPgs), - fCurPacketHasBeenSynchronizedUsingRTCP(False), - fRTPPayloadFormat(rtpPayloadFormat), - fTimestampFrequency(rtpTimestampFrequency), - fSSRC(our_random32()) { - fReceptionStatsDB = new RTPReceptionStatsDB(*this); -} - -RTPSource::~RTPSource() { - delete fReceptionStatsDB; -} - -void RTPSource::getAttributes() const { - envir().setResultMsg(""); // Fix later to get attributes from header ##### -} - - -////////// RTPReceptionStatsDB ////////// - -RTPReceptionStatsDB::RTPReceptionStatsDB(RTPSource& rtpSource) - : fOurRTPSource(rtpSource), - fTable(HashTable::create(ONE_WORD_HASH_KEYS)), fTotNumPacketsReceived(0) { - reset(); -} - -void RTPReceptionStatsDB::reset() { - fNumActiveSourcesSinceLastReset = 0; - - Iterator iter(*this); - RTPReceptionStats* stats; - while ((stats = iter.next()) != NULL) { - stats->reset(); - } -} - -RTPReceptionStatsDB::~RTPReceptionStatsDB() { - // First, remove and delete all stats records from the table: - RTPReceptionStats* stats; - while ((stats = (RTPReceptionStats*)fTable->RemoveNext()) != NULL) { - delete stats; - } - - // Then, delete the table itself: - delete fTable; -} - -void RTPReceptionStatsDB -::noteIncomingPacket(u_int32_t SSRC, u_int16_t seqNum, - u_int32_t rtpTimestamp, unsigned timestampFrequency, - Boolean useForJitterCalculation, - struct timeval& resultPresentationTime, - Boolean& resultHasBeenSyncedUsingRTCP, - unsigned packetSize) { - ++fTotNumPacketsReceived; - RTPReceptionStats* stats = lookup(SSRC); - if (stats == NULL) { - // This is the first time we've heard from this SSRC. - // Create a new record for it: - stats = new RTPReceptionStats(fOurRTPSource, SSRC, seqNum); - if (stats == NULL) return; - add(SSRC, stats); - } - - if (stats->numPacketsReceivedSinceLastReset() == 0) { - ++fNumActiveSourcesSinceLastReset; - } - - stats->noteIncomingPacket(seqNum, rtpTimestamp, timestampFrequency, - useForJitterCalculation, - resultPresentationTime, - resultHasBeenSyncedUsingRTCP, packetSize); -} - -void RTPReceptionStatsDB -::noteIncomingSR(u_int32_t SSRC, - u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, - u_int32_t rtpTimestamp) { - RTPReceptionStats* stats = lookup(SSRC); - if (stats == NULL) { - // This is the first time we've heard of this SSRC. - // Create a new record for it: - stats = new RTPReceptionStats(fOurRTPSource, SSRC); - if (stats == NULL) return; - add(SSRC, stats); - } - - stats->noteIncomingSR(ntpTimestampMSW, ntpTimestampLSW, rtpTimestamp); -} - -void RTPReceptionStatsDB::removeRecord(u_int32_t SSRC) { - RTPReceptionStats* stats = lookup(SSRC); - if (stats != NULL) { - long SSRC_long = (long)SSRC; - fTable->Remove((char const*)SSRC_long); - delete stats; - } -} - -RTPReceptionStatsDB::Iterator -::Iterator(RTPReceptionStatsDB& receptionStatsDB) - : fIter(HashTable::Iterator::create(*(receptionStatsDB.fTable))) { -} - -RTPReceptionStatsDB::Iterator::~Iterator() { - delete fIter; -} - -RTPReceptionStats* -RTPReceptionStatsDB::Iterator::next(Boolean includeInactiveSources) { - char const* key; // dummy - - // If asked, skip over any sources that haven't been active - // since the last reset: - RTPReceptionStats* stats; - do { - stats = (RTPReceptionStats*)(fIter->next(key)); - } while (stats != NULL && !includeInactiveSources - && stats->numPacketsReceivedSinceLastReset() == 0); - - return stats; -} - -RTPReceptionStats* RTPReceptionStatsDB::lookup(u_int32_t SSRC) const { - long SSRC_long = (long)SSRC; - return (RTPReceptionStats*)(fTable->Lookup((char const*)SSRC_long)); -} - -void RTPReceptionStatsDB::add(u_int32_t SSRC, RTPReceptionStats* stats) { - long SSRC_long = (long)SSRC; - fTable->Add((char const*)SSRC_long, stats); -} - -////////// RTPReceptionStats ////////// - -RTPReceptionStats::RTPReceptionStats(RTPSource& rtpSource, u_int32_t SSRC, - u_int16_t initialSeqNum) - : fOurRTPSource(rtpSource) { - initSeqNum(initialSeqNum); - init(SSRC); -} - -RTPReceptionStats::RTPReceptionStats(RTPSource& rtpSource, u_int32_t SSRC) - : fOurRTPSource(rtpSource) { - init(SSRC); -} - -RTPReceptionStats::~RTPReceptionStats() { -} - -void RTPReceptionStats::init(u_int32_t SSRC) { - fSSRC = SSRC; - fTotNumPacketsReceived = 0; - fTotBytesReceived_hi = fTotBytesReceived_lo = 0; - fHaveSeenInitialSequenceNumber = False; - fLastTransit = ~0; - fPreviousPacketRTPTimestamp = 0; - fJitter = 0.0; - fLastReceivedSR_NTPmsw = fLastReceivedSR_NTPlsw = 0; - fLastReceivedSR_time.tv_sec = fLastReceivedSR_time.tv_usec = 0; - fLastPacketReceptionTime.tv_sec = fLastPacketReceptionTime.tv_usec = 0; - fMinInterPacketGapUS = 0x7FFFFFFF; - fMaxInterPacketGapUS = 0; - fTotalInterPacketGaps.tv_sec = fTotalInterPacketGaps.tv_usec = 0; - fHasBeenSynchronized = False; - fSyncTime.tv_sec = fSyncTime.tv_usec = 0; - reset(); -} - -void RTPReceptionStats::initSeqNum(u_int16_t initialSeqNum) { - fBaseExtSeqNumReceived = initialSeqNum-1; - fHighestExtSeqNumReceived = initialSeqNum; - fHaveSeenInitialSequenceNumber = True; -} - -#ifndef MILLION -#define MILLION 1000000 -#endif - -void RTPReceptionStats -::noteIncomingPacket(u_int16_t seqNum, u_int32_t rtpTimestamp, - unsigned timestampFrequency, - Boolean useForJitterCalculation, - struct timeval& resultPresentationTime, - Boolean& resultHasBeenSyncedUsingRTCP, - unsigned packetSize) { - if (!fHaveSeenInitialSequenceNumber) initSeqNum(seqNum); - - ++fNumPacketsReceivedSinceLastReset; - ++fTotNumPacketsReceived; - u_int32_t prevTotBytesReceived_lo = fTotBytesReceived_lo; - fTotBytesReceived_lo += packetSize; - if (fTotBytesReceived_lo < prevTotBytesReceived_lo) { // wrap-around - ++fTotBytesReceived_hi; - } - - // Check whether the sequence number has wrapped around: - unsigned seqNumCycle = (fHighestExtSeqNumReceived&0xFFFF0000); - unsigned oldSeqNum = (fHighestExtSeqNumReceived&0xFFFF); - unsigned seqNumDifference = (unsigned)((int)seqNum-(int)oldSeqNum); - if (seqNumDifference >= 0x8000 - && seqNumLT((u_int16_t)oldSeqNum, seqNum)) { - // sequence number wrapped around => start a new cycle: - seqNumCycle += 0x10000; - } - - unsigned newSeqNum = seqNumCycle|seqNum; - if (newSeqNum > fHighestExtSeqNumReceived) { - fHighestExtSeqNumReceived = newSeqNum; - } - - // Record the inter-packet delay - struct timeval timeNow; - gettimeofday(&timeNow, NULL); - if (fLastPacketReceptionTime.tv_sec != 0 - || fLastPacketReceptionTime.tv_usec != 0) { - unsigned gap - = (timeNow.tv_sec - fLastPacketReceptionTime.tv_sec)*MILLION - + timeNow.tv_usec - fLastPacketReceptionTime.tv_usec; - if (gap > fMaxInterPacketGapUS) { - fMaxInterPacketGapUS = gap; - } - if (gap < fMinInterPacketGapUS) { - fMinInterPacketGapUS = gap; - } - fTotalInterPacketGaps.tv_usec += gap; - if (fTotalInterPacketGaps.tv_usec >= MILLION) { - ++fTotalInterPacketGaps.tv_sec; - fTotalInterPacketGaps.tv_usec -= MILLION; - } - } - fLastPacketReceptionTime = timeNow; - - // Compute the current 'jitter' using the received packet's RTP timestamp, - // and the RTP timestamp that would correspond to the current time. - // (Use the code from appendix A.8 in the RTP spec.) - // Note, however, that we don't use this packet if its timestamp is - // the same as that of the previous packet (this indicates a multi-packet - // fragment), or if we've been explicitly told not to use this packet. - if (useForJitterCalculation - && rtpTimestamp != fPreviousPacketRTPTimestamp) { - unsigned arrival = (timestampFrequency*timeNow.tv_sec); - arrival += (unsigned) - ((2.0*timestampFrequency*timeNow.tv_usec + 1000000.0)/2000000); - // note: rounding - int transit = arrival - rtpTimestamp; - if (fLastTransit == (~0)) fLastTransit = transit; // hack for first time - int d = transit - fLastTransit; - fLastTransit = transit; - if (d < 0) d = -d; - fJitter += (1.0/16.0) * ((double)d - fJitter); - } - - // Return the 'presentation time' that corresponds to "rtpTimestamp": - if (fSyncTime.tv_sec == 0 && fSyncTime.tv_usec == 0) { - // This is the first timestamp that we've seen, so use the current - // 'wall clock' time as the synchronization time. (This will be - // corrected later when we receive RTCP SRs.) - fSyncTimestamp = rtpTimestamp; - fSyncTime = timeNow; - } - - int timestampDiff = rtpTimestamp - fSyncTimestamp; - // Note: This works even if the timestamp wraps around - // (as long as "int" is 32 bits) - - // Divide this by the timestamp frequency to get real time: - double timeDiff - = timestampDiff/(double)(fOurRTPSource.timestampFrequency()); - - // Add this to the 'sync time' to get our result: - unsigned const million = 1000000; - unsigned seconds, uSeconds; - if (timeDiff >= 0.0) { - seconds = fSyncTime.tv_sec + (unsigned)(timeDiff); - uSeconds = fSyncTime.tv_usec - + (unsigned)((timeDiff - (unsigned)timeDiff)*million); - if (uSeconds >= million) { - uSeconds -= million; - ++seconds; - } - } else { - timeDiff = -timeDiff; - seconds = fSyncTime.tv_sec - (unsigned)(timeDiff); - uSeconds = fSyncTime.tv_usec - - (unsigned)((timeDiff - (unsigned)timeDiff)*million); - if ((int)uSeconds < 0) { - uSeconds += million; - --seconds; - } - } - resultPresentationTime.tv_sec = seconds; - resultPresentationTime.tv_usec = uSeconds; - resultHasBeenSyncedUsingRTCP = fHasBeenSynchronized; - - // Save these as the new synchronization timestamp & time: - fSyncTimestamp = rtpTimestamp; - fSyncTime = resultPresentationTime; - - fPreviousPacketRTPTimestamp = rtpTimestamp; -} - -void RTPReceptionStats::noteIncomingSR(u_int32_t ntpTimestampMSW, - u_int32_t ntpTimestampLSW, - u_int32_t rtpTimestamp) { - fLastReceivedSR_NTPmsw = ntpTimestampMSW; - fLastReceivedSR_NTPlsw = ntpTimestampLSW; - - gettimeofday(&fLastReceivedSR_time, NULL); - - // Use this SR to update time synchronization information: - fSyncTimestamp = rtpTimestamp; - fSyncTime.tv_sec = ntpTimestampMSW - 0x83AA7E80; // 1/1/1900 -> 1/1/1970 - double microseconds = (ntpTimestampLSW*15625.0)/0x04000000; // 10^6/2^32 - fSyncTime.tv_usec = (unsigned)(microseconds+0.5); - fHasBeenSynchronized = True; -} - -double RTPReceptionStats::totNumKBytesReceived() const { - double const hiMultiplier = 0x20000000/125.0; // == (2^32)/(10^3) - return fTotBytesReceived_hi*hiMultiplier + fTotBytesReceived_lo/1000.0; -} - -unsigned RTPReceptionStats::jitter() const { - return (unsigned)fJitter; -} - -void RTPReceptionStats::reset() { - fNumPacketsReceivedSinceLastReset = 0; - fLastResetExtSeqNumReceived = fHighestExtSeqNumReceived; -} - -Boolean seqNumLT(u_int16_t s1, u_int16_t s2) { - // a 'less-than' on 16-bit sequence numbers - int diff = s2-s1; - if (diff > 0) { - return (diff < 0x8000); - } else if (diff < 0) { - return (diff < -0x8000); - } else { // diff == 0 - return False; - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/RTSPClient.cpp b/mythtv/libs/libmythlivemedia/liveMedia/RTSPClient.cpp deleted file mode 100644 index 46619b040c4..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/RTSPClient.cpp +++ /dev/null @@ -1,2470 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A generic RTSP client -// Implementation - -#include "RTSPClient.hh" -#include "RTSPCommon.hh" -#include "Base64.hh" -#include -#include "our_md5.h" -#ifdef SUPPORT_REAL_RTSP -#include "../RealRTSP/include/RealRTSP.hh" -#endif - -// Experimental support for temporarily setting the locale (e.g., to POSIX, -// for parsing or printing floating-point numbers in protocol headers). -#ifdef USE_LOCALE -#include -#else -#ifndef LC_NUMERIC -#define LC_NUMERIC 0 -#endif -#endif - -class Locale { -public: - Locale(char const* newLocale, int category = LC_NUMERIC) - : fCategory(category) { -#ifdef USE_LOCALE - fPrevLocale = strDup(setlocale(category, NULL)); - setlocale(category, newLocale); -#endif - } - - virtual ~Locale() { -#ifdef USE_LOCALE - if (fPrevLocale != NULL) { - setlocale(fCategory, fPrevLocale); - delete[] fPrevLocale; - } -#endif - } - -private: - int fCategory; - char* fPrevLocale; -}; - - - -////////// RTSPClient ////////// - -RTSPClient* RTSPClient::createNew(UsageEnvironment& env, - int verbosityLevel, - char const* applicationName, - portNumBits tunnelOverHTTPPortNum) { - return new RTSPClient(env, verbosityLevel, - applicationName, tunnelOverHTTPPortNum); -} - -Boolean RTSPClient::lookupByName(UsageEnvironment& env, - char const* instanceName, - RTSPClient*& resultClient) { - resultClient = NULL; // unless we succeed - - Medium* medium; - if (!Medium::lookupByName(env, instanceName, medium)) return False; - - if (!medium->isRTSPClient()) { - env.setResultMsg(instanceName, " is not a RTSP client"); - return False; - } - - resultClient = (RTSPClient*)medium; - return True; -} - -unsigned RTSPClient::fCSeq = 0; - -RTSPClient::RTSPClient(UsageEnvironment& env, - int verbosityLevel, char const* applicationName, - portNumBits tunnelOverHTTPPortNum) - : Medium(env), - fVerbosityLevel(verbosityLevel), - fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum), - fInputSocketNum(-1), fOutputSocketNum(-1), fServerAddress(0), - fBaseURL(NULL), fTCPStreamIdCount(0), fLastSessionId(NULL), - fSessionTimeoutParameter(0), -#ifdef SUPPORT_REAL_RTSP - fRealChallengeStr(NULL), fRealETagStr(NULL), -#endif - fServerIsKasenna(False), fKasennaContentType(NULL), - fServerIsMicrosoft(False) -{ - fResponseBufferSize = 20000; - fResponseBuffer = new char[fResponseBufferSize+1]; - - // Set the "User-Agent:" header to use in each request: - char const* const libName = "LIVE555 Streaming Media v"; - char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; - char const* libPrefix; char const* libSuffix; - if (applicationName == NULL || applicationName[0] == '\0') { - applicationName = libPrefix = libSuffix = ""; - } else { - libPrefix = " ("; - libSuffix = ")"; - } - char const* const formatStr = "User-Agent: %s%s%s%s%s\r\n"; - unsigned headerSize - = strlen(formatStr) + strlen(applicationName) + strlen(libPrefix) - + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix); - fUserAgentHeaderStr = new char[headerSize]; - sprintf(fUserAgentHeaderStr, formatStr, - applicationName, libPrefix, libName, libVersionStr, libSuffix); - fUserAgentHeaderStrSize = strlen(fUserAgentHeaderStr); -} - -void RTSPClient::setUserAgentString(char const* userAgentStr) { - if (userAgentStr == NULL) return; - - // Change the existing user agent header string: - char const* const formatStr = "User-Agent: %s\r\n"; - unsigned headerSize = strlen(formatStr) + strlen(userAgentStr); - delete[] fUserAgentHeaderStr; - fUserAgentHeaderStr = new char[headerSize]; - sprintf(fUserAgentHeaderStr, formatStr, userAgentStr); - fUserAgentHeaderStrSize = strlen(fUserAgentHeaderStr); -} - -RTSPClient::~RTSPClient() { - reset(); - envir().taskScheduler().turnOffBackgroundReadHandling(fInputSocketNum); - delete[] fResponseBuffer; - delete[] fUserAgentHeaderStr; -} - -Boolean RTSPClient::isRTSPClient() const { - return True; -} - -void RTSPClient::resetTCPSockets() { - if (fInputSocketNum >= 0) { - ::closeSocket(fInputSocketNum); - if (fOutputSocketNum != fInputSocketNum) ::closeSocket(fOutputSocketNum); - } - fInputSocketNum = fOutputSocketNum = -1; -} - -void RTSPClient::reset() { - resetTCPSockets(); - fServerAddress = 0; - - delete[] fBaseURL; fBaseURL = NULL; - - fCurrentAuthenticator.reset(); - - delete[] fKasennaContentType; fKasennaContentType = NULL; -#ifdef SUPPORT_REAL_RTSP - delete[] fRealChallengeStr; fRealChallengeStr = NULL; - delete[] fRealETagStr; fRealETagStr = NULL; -#endif - delete[] fLastSessionId; fLastSessionId = NULL; -} - -static char* getLine(char* startOfLine) { - // returns the start of the next line, or NULL if none - for (char* ptr = startOfLine; *ptr != '\0'; ++ptr) { - if (*ptr == '\r' || *ptr == '\n') { - // We found the end of the line - *ptr++ = '\0'; - if (*ptr == '\n') ++ptr; - return ptr; - } - } - - return NULL; -} - -char* RTSPClient::describeURL(char const* url, Authenticator* authenticator, - Boolean allowKasennaProtocol) { - char* cmd = NULL; - fDescribeStatusCode = 0; - do { - // First, check whether "url" contains a username:password to be used: - char* username; char* password; - if (authenticator == NULL - && parseRTSPURLUsernamePassword(url, username, password)) { - char* result = describeWithPassword(url, username, password); - delete[] username; delete[] password; // they were dynamically allocated - return result; - } - - if (!openConnectionFromURL(url, authenticator)) break; - - // Send the DESCRIBE command: - - // First, construct an authenticator string: - fCurrentAuthenticator.reset(); - char* authenticatorStr - = createAuthenticatorString(authenticator, "DESCRIBE", url); - - char const* acceptStr = allowKasennaProtocol - ? "Accept: application/x-rtsp-mh, application/sdp\r\n" - : "Accept: application/sdp\r\n"; - - // (Later implement more, as specified in the RTSP spec, sec D.1 #####) - char* const cmdFmt = - "DESCRIBE %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "%s" - "%s" - "%s" -#ifdef SUPPORT_REAL_RTSP - REAL_DESCRIBE_HEADERS -#endif - "\r\n"; - unsigned cmdSize = strlen(cmdFmt) - + strlen(url) - + 20 /* max int len */ - + strlen(acceptStr) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - url, - ++fCSeq, - acceptStr, - authenticatorStr, - fUserAgentHeaderStr); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "DESCRIBE")) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("DESCRIBE", bytesRead, responseCode, firstLine, nextLineStart, - False /*don't check for response code 200*/)) break; - - // Inspect the first line to check whether it's a result code that - // we can handle. - Boolean wantRedirection = False; - char* redirectionURL = NULL; -#ifdef SUPPORT_REAL_RTSP - delete[] fRealETagStr; fRealETagStr = new char[fResponseBufferSize]; -#endif - if (responseCode == 301 || responseCode == 302) { - wantRedirection = True; - redirectionURL = new char[fResponseBufferSize]; // ensures enough space - } else if (responseCode != 200) { - checkForAuthenticationFailure(responseCode, nextLineStart, authenticator); - envir().setResultMsg("cannot handle DESCRIBE response: ", firstLine); - break; - } - - // Skip every subsequent header line, until we see a blank line - // The remaining data is assumed to be the SDP descriptor that we want. - // We should really do some checking on the headers here - e.g., to - // check for "Content-type: application/sdp", "Content-base", - // "Content-location", "CSeq", etc. ##### - char* serverType = new char[fResponseBufferSize]; // ensures enough space - int contentLength = -1; - char* lineStart; - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - if (lineStart[0] == '\0') break; // this is a blank line - - if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1 - || sscanf(lineStart, "Content-length: %d", &contentLength) == 1) { - if (contentLength < 0) { - envir().setResultMsg("Bad \"Content-length:\" header: \"", - lineStart, "\""); - break; - } - } else if (sscanf(lineStart, "Server: %s", serverType) == 1) { - if (strncmp(serverType, "Kasenna", 7) == 0) fServerIsKasenna = True; - if (strncmp(serverType, "WMServer", 8) == 0) fServerIsMicrosoft = True; -#ifdef SUPPORT_REAL_RTSP - } else if (sscanf(lineStart, "ETag: %s", fRealETagStr) == 1) { -#endif - } else if (wantRedirection) { - if (sscanf(lineStart, "Location: %s", redirectionURL) == 1) { - // Try again with this URL - if (fVerbosityLevel >= 1) { - envir() << "Redirecting to the new URL \"" - << redirectionURL << "\"\n"; - } - reset(); - char* result = describeURL(redirectionURL); - delete[] redirectionURL; - delete[] serverType; - delete[] cmd; - return result; - } - } - } - delete[] serverType; - - // We're now at the end of the response header lines - if (wantRedirection) { - envir().setResultMsg("Saw redirection response code, but not a \"Location:\" header"); - delete[] redirectionURL; - break; - } - if (lineStart == NULL) { - envir().setResultMsg("no content following header lines: ", fResponseBuffer); - break; - } - - // Use the remaining data as the SDP descr, but first, check - // the "Content-length:" header (if any) that we saw. We may need to - // read more data, or we may have extraneous data in the buffer. - char* bodyStart = nextLineStart; - if (contentLength >= 0) { - // We saw a "Content-length:" header - unsigned numBodyBytes = &firstLine[bytesRead] - bodyStart; - if (contentLength > (int)numBodyBytes) { - // We need to read more data. First, make sure we have enough - // space for it: - unsigned numExtraBytesNeeded = contentLength - numBodyBytes; - unsigned remainingBufferSize - = fResponseBufferSize - (bytesRead + (firstLine - fResponseBuffer)); - if (numExtraBytesNeeded > remainingBufferSize) { - char tmpBuf[200]; - sprintf(tmpBuf, "Read buffer size (%d) is too small for \"Content-length:\" %d (need a buffer size of >= %d bytes\n", - fResponseBufferSize, contentLength, - fResponseBufferSize + numExtraBytesNeeded - remainingBufferSize); - envir().setResultMsg(tmpBuf); - break; - } - - // Keep reading more data until we have enough: - if (fVerbosityLevel >= 1) { - envir() << "Need to read " << numExtraBytesNeeded - << " extra bytes\n"; - } - while (numExtraBytesNeeded > 0) { - struct sockaddr_in fromAddress; - char* ptr = &firstLine[bytesRead]; - int bytesRead2 = readSocket(envir(), fInputSocketNum, (unsigned char*)ptr, - numExtraBytesNeeded, fromAddress); - if (bytesRead2 < 0) break; - ptr[bytesRead2] = '\0'; - if (fVerbosityLevel >= 1) { - envir() << "Read " << bytesRead2 << " extra bytes: " - << ptr << "\n"; - } - - bytesRead += bytesRead2; - numExtraBytesNeeded -= bytesRead2; - } - if (numExtraBytesNeeded > 0) break; // one of the reads failed - } - - // Remove any '\0' characters from inside the SDP description. - // Any such characters would violate the SDP specification, but - // some RTSP servers have been known to include them: - int from, to = 0; - for (from = 0; from < contentLength; ++from) { - if (bodyStart[from] != '\0') { - if (to != from) bodyStart[to] = bodyStart[from]; - ++to; - } - } - if (from != to && fVerbosityLevel >= 1) { - envir() << "Warning: " << from-to << " invalid 'NULL' bytes were found in (and removed from) the SDP description.\n"; - } - bodyStart[to] = '\0'; // trims any extra data - } - - ////////// BEGIN Kasenna BS ////////// - // If necessary, handle Kasenna's non-standard BS response: - if (fServerIsKasenna && strncmp(bodyStart, "", 18) == 0) { - // Translate from x-rtsp-mh to sdp - int videoPid, audioPid; - u_int64_t mh_duration; - char* currentWord = new char[fResponseBufferSize]; // ensures enough space - delete[] fKasennaContentType; - fKasennaContentType = new char[fResponseBufferSize]; // ensures enough space - char* currentPos = bodyStart; - - while (strcmp(currentWord, "") != 0) { - sscanf(currentPos, "%s", currentWord); - - if (strcmp(currentWord, "VideoPid") == 0) { - currentPos += strlen(currentWord) + 1; - sscanf(currentPos, "%s", currentWord); - currentPos += strlen(currentWord) + 1; - sscanf(currentPos, "%d", &videoPid); - currentPos += 3; - } - - if (strcmp(currentWord, "AudioPid") == 0) { - currentPos += strlen(currentWord) + 1; - sscanf(currentPos, "%s", currentWord); - currentPos += strlen(currentWord) + 1; - sscanf(currentPos, "%d", &audioPid); - currentPos += 3; - } - - if (strcmp(currentWord, "Duration") == 0) { - currentPos += strlen(currentWord) + 1; - sscanf(currentPos, "%s", currentWord); - currentPos += strlen(currentWord) + 1; - sscanf(currentPos, "%llu", &mh_duration); - currentPos += 3; - } - - if (strcmp(currentWord, "TypeSpecificData") == 0) { - currentPos += strlen(currentWord) + 1; - sscanf(currentPos, "%s", currentWord); - currentPos += strlen(currentWord) + 1; - sscanf(currentPos, "%s", fKasennaContentType); - currentPos += 3; - printf("Kasenna Content Type: %s\n", fKasennaContentType); - } - - currentPos += strlen(currentWord) + 1; - } - - if (fKasennaContentType != NULL - && strcmp(fKasennaContentType, "PARTNER_41_MPEG-4") == 0) { - char* describeSDP = describeURL(url, authenticator, True); - - delete[] currentWord; - delete[] cmd; - return describeSDP; - } - - unsigned char byte1 = fServerAddress & 0x000000ff; - unsigned char byte2 = (fServerAddress & 0x0000ff00) >> 8; - unsigned char byte3 = (fServerAddress & 0x00ff0000) >> 16; - unsigned char byte4 = (fServerAddress & 0xff000000) >> 24; - - char const* sdpFmt = - "v=0\r\n" - "o=NoSpacesAllowed 1 1 IN IP4 %u.%u.%u.%u\r\n" - "s=%s\r\n" - "c=IN IP4 %u.%u.%u.%u\r\n" - "t=0 0\r\n" - "a=control:*\r\n" - "a=range:npt=0-%llu\r\n" - "m=video 1554 RAW/RAW/UDP 33\r\n" - "a=control:trackID=%d\r\n"; - unsigned sdpBufSize = strlen(sdpFmt) - + 4*3 // IP address - + strlen(url) - + 20 // max int length - + 20; // max int length - char* sdpBuf = new char[sdpBufSize]; - sprintf(sdpBuf, sdpFmt, - byte1, byte2, byte3, byte4, - url, - byte1, byte2, byte3, byte4, - mh_duration/1000000, - videoPid); - - char* result = strDup(sdpBuf); - delete[] sdpBuf; delete[] currentWord; - delete[] cmd; - return result; - } - ////////// END Kasenna BS ////////// - - delete[] cmd; - return strDup(bodyStart); - } while (0); - - delete[] cmd; - if (fDescribeStatusCode == 0) fDescribeStatusCode = 2; - return NULL; -} - -char* RTSPClient -::describeWithPassword(char const* url, - char const* username, char const* password) { - Authenticator authenticator; - authenticator.setUsernameAndPassword(username, password); - char* describeResult = describeURL(url, &authenticator); - if (describeResult != NULL) { - // We are already authorized - return describeResult; - } - - // The "realm" field should have been filled in: - if (authenticator.realm() == NULL) { - // We haven't been given enough information to try again, so fail: - return NULL; - } - - // Try again: - describeResult = describeURL(url, &authenticator); - if (describeResult != NULL) { - // The authenticator worked, so use it in future requests: - fCurrentAuthenticator = authenticator; - } - - return describeResult; -} - -char* RTSPClient::sendOptionsCmd(char const* url, - char* username, char* password, - Authenticator* authenticator) { - char* result = NULL; - char* cmd = NULL; - Boolean haveAllocatedAuthenticator = False; - do { - if (authenticator == NULL) { - // First, check whether "url" contains a username:password to be used - // (and no username,password pair was supplied separately): - if (username == NULL && password == NULL - && parseRTSPURLUsernamePassword(url, username, password)) { - Authenticator authenticator; - authenticator.setUsernameAndPassword(username, password); - result = sendOptionsCmd(url, username, password, &authenticator); - delete[] username; delete[] password; // they were dynamically allocated - break; - } else if (username != NULL && password != NULL) { - // Use the separately supplied username and password: - authenticator = new Authenticator; - haveAllocatedAuthenticator = True; - authenticator->setUsernameAndPassword(username, password); - - result = sendOptionsCmd(url, username, password, authenticator); - if (result != NULL) break; // We are already authorized - - // The "realm" field should have been filled in: - if (authenticator->realm() == NULL) { - // We haven't been given enough information to try again, so fail: - break; - } - // Try again: - } - } - - if (!openConnectionFromURL(url, authenticator)) break; - - // Send the OPTIONS command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(authenticator, "OPTIONS", url); - - char* const cmdFmt = - "OPTIONS %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "%s" - "%s" -#ifdef SUPPORT_REAL_RTSP - REAL_OPTIONS_HEADERS -#endif - "\r\n"; - unsigned cmdSize = strlen(cmdFmt) - + strlen(url) - + 20 /* max int len */ - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - url, - ++fCSeq, - authenticatorStr, - fUserAgentHeaderStr); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "OPTIONS")) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("OPTIONS", bytesRead, responseCode, firstLine, nextLineStart, - False /*don't check for response code 200*/)) break; - if (responseCode != 200) { - checkForAuthenticationFailure(responseCode, nextLineStart, authenticator); - envir().setResultMsg("cannot handle OPTIONS response: ", firstLine); - break; - } - - // Look for a "Public:" header (which will contain our result str): - char* lineStart; - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - - if (_strncasecmp(lineStart, "Public: ", 8) == 0) { - delete[] result; result = strDup(&lineStart[8]); -#ifdef SUPPORT_REAL_RTSP - } else if (_strncasecmp(lineStart, "RealChallenge1: ", 16) == 0) { - delete[] fRealChallengeStr; fRealChallengeStr = strDup(&lineStart[16]); -#endif - } - } - } while (0); - - delete[] cmd; - if (haveAllocatedAuthenticator) delete authenticator; - return result; -} - -static Boolean isAbsoluteURL(char const* url) { - // Assumption: "url" is absolute if it contains a ':', before any - // occurrence of '/' - while (*url != '\0' && *url != '/') { - if (*url == ':') return True; - ++url; - } - - return False; -} - -void RTSPClient::constructSubsessionURL(MediaSubsession const& subsession, - char const*& prefix, - char const*& separator, - char const*& suffix) { - // Figure out what the URL describing "subsession" will look like. - // The URL is returned in three parts: prefix; separator; suffix - //##### NOTE: This code doesn't really do the right thing if "fBaseURL" - // doesn't end with a "/", and "subsession.controlPath()" is relative. - // The right thing would have been to truncate "fBaseURL" back to the - // rightmost "/", and then add "subsession.controlPath()". - // In practice, though, each "DESCRIBE" response typically contains - // a "Content-Base:" header that consists of "fBaseURL" followed by - // a "/", in which case this code ends up giving the correct result. - // However, we should really fix this code to do the right thing, and - // also check for and use the "Content-Base:" header appropriately. ##### - prefix = fBaseURL; - if (prefix == NULL) prefix = ""; - - suffix = subsession.controlPath(); - if (suffix == NULL) suffix = ""; - - if (isAbsoluteURL(suffix)) { - prefix = separator = ""; - } else { - unsigned prefixLen = strlen(prefix); - separator = (prefix[prefixLen-1] == '/' || suffix[0] == '/') ? "" : "/"; - } -} - -Boolean RTSPClient::announceSDPDescription(char const* url, - char const* sdpDescription, - Authenticator* authenticator) { - char* cmd = NULL; - do { - if (!openConnectionFromURL(url, authenticator)) break; - - // Send the ANNOUNCE command: - - // First, construct an authenticator string: - fCurrentAuthenticator.reset(); - char* authenticatorStr - = createAuthenticatorString(authenticator, "ANNOUNCE", url); - - char* const cmdFmt = - "ANNOUNCE %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Content-Type: application/sdp\r\n" - "%s" - "Content-length: %d\r\n\r\n" - "%s"; - // Note: QTSS hangs if an "ANNOUNCE" contains a "User-Agent:" field (go figure), so don't include one here - unsigned sdpSize = strlen(sdpDescription); - unsigned cmdSize = strlen(cmdFmt) - + strlen(url) - + 20 /* max int len */ - + strlen(authenticatorStr) - + 20 /* max int len */ - + sdpSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - url, - ++fCSeq, - authenticatorStr, - sdpSize, - sdpDescription); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "ANNOUNCE")) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("ANNOUNCE", bytesRead, responseCode, firstLine, nextLineStart, - False /*don't check for response code 200*/)) break; - - // Inspect the first line to check whether it's a result code 200 - if (responseCode != 200) { - checkForAuthenticationFailure(responseCode, nextLineStart, authenticator); - envir().setResultMsg("cannot handle ANNOUNCE response: ", firstLine); - break; - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient -::announceWithPassword(char const* url, char const* sdpDescription, - char const* username, char const* password) { - Authenticator authenticator; - authenticator.setUsernameAndPassword(username, password); - if (announceSDPDescription(url, sdpDescription, &authenticator)) { - // We are already authorized - return True; - } - - // The "realm" field should have been filled in: - if (authenticator.realm() == NULL) { - // We haven't been given enough information to try again, so fail: - return False; - } - - // Try again: - Boolean secondTrySuccess - = announceSDPDescription(url, sdpDescription, &authenticator); - - if (secondTrySuccess) { - // The authenticator worked, so use it in future requests: - fCurrentAuthenticator = authenticator; - } - - return secondTrySuccess; -} - -Boolean RTSPClient::setupMediaSubsession(MediaSubsession& subsession, - Boolean streamOutgoing, - Boolean streamUsingTCP, - Boolean forceMulticastOnUnspecified) { - char* cmd = NULL; - char* setupStr = NULL; - - if (fServerIsMicrosoft) { - // Microsoft doesn't send the right endTime on live streams. Correct this: - char *tmpStr = subsession.parentSession().mediaSessionType(); - if (tmpStr != NULL && strncmp(tmpStr, "broadcast", 9) == 0) { - subsession.parentSession().playEndTime() = 0.0; - } - } - - do { - // Construct the SETUP command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, - "SETUP", fBaseURL); - - // When sending more than one "SETUP" request, include a "Session:" - // header in the 2nd and later "SETUP"s. - char* sessionStr; - if (fLastSessionId != NULL) { - sessionStr = new char[20+strlen(fLastSessionId)]; - sprintf(sessionStr, "Session: %s\r\n", fLastSessionId); - } else { - sessionStr = ""; - } - - char* transportStr = NULL; -#ifdef SUPPORT_REAL_RTSP - if (usingRealNetworksChallengeResponse()) { - // Use a special "Transport:" header, and also add a 'challenge response'. - char challenge2[64]; - char checksum[34]; - RealCalculateChallengeResponse(fRealChallengeStr, challenge2, checksum); - - char const* etag = fRealETagStr == NULL ? "" : fRealETagStr; - - char* transportHeader; - if (subsession.parentSession().isRealNetworksRDT) { - transportHeader = strDup("Transport: x-pn-tng/tcp;mode=play,rtp/avp/unicast;mode=play\r\n"); - } else { - // Use a regular "Transport:" header: - char const* transportHeaderFmt - = "Transport: RTP/AVP%s%s=%d-%d\r\n"; - char const* transportTypeStr; - char const* portTypeStr; - unsigned short rtpNumber, rtcpNumber; - if (streamUsingTCP) { // streaming over the RTSP connection - transportTypeStr = "/TCP;unicast"; - portTypeStr = ";interleaved"; - rtpNumber = fTCPStreamIdCount++; - rtcpNumber = fTCPStreamIdCount++; - } else { // normal RTP streaming - unsigned connectionAddress = subsession.connectionEndpointAddress(); - Boolean requestMulticastStreaming = IsMulticastAddress(connectionAddress) - || (connectionAddress == 0 && forceMulticastOnUnspecified); - transportTypeStr = requestMulticastStreaming ? ";multicast" : ";unicast"; - portTypeStr = ";client_port"; - rtpNumber = subsession.clientPortNum(); - if (rtpNumber == 0) { - envir().setResultMsg("Client port number unknown\n"); - break; - } - rtcpNumber = rtpNumber + 1; - } - - unsigned transportHeaderSize = strlen(transportHeaderFmt) - + strlen(transportTypeStr) + strlen(portTypeStr) + 2*5 /* max port len */; - transportHeader = new char[transportHeaderSize]; - sprintf(transportHeader, transportHeaderFmt, - transportTypeStr, portTypeStr, rtpNumber, rtcpNumber); - } - char const* transportFmt = - "%s" - "RealChallenge2: %s, sd=%s\r\n" - "If-Match: %s\r\n"; - unsigned transportSize = strlen(transportFmt) - + strlen(transportHeader) - + sizeof challenge2 + sizeof checksum - + strlen(etag); - transportStr = new char[transportSize]; - sprintf(transportStr, transportFmt, - transportHeader, - challenge2, checksum, - etag); - delete[] transportHeader; - - if (subsession.parentSession().isRealNetworksRDT) { - // Also, tell the RDT source to use the RTSP TCP socket: - RealRDTSource* rdtSource - = (RealRDTSource*)(subsession.readSource()); - rdtSource->setInputSocket(fInputSocketNum); - } - } -#endif - - char const *prefix, *separator, *suffix; - constructSubsessionURL(subsession, prefix, separator, suffix); - char* transportFmt; - - if (strcmp(subsession.protocolName(), "UDP") == 0) { - char const* setupFmt = "SETUP %s%s RTSP/1.0\r\n"; - unsigned setupSize = strlen(setupFmt) - + strlen(prefix) + strlen (separator); - setupStr = new char[setupSize]; - sprintf(setupStr, setupFmt, prefix, separator); - - transportFmt = "Transport: RAW/RAW/UDP%s%s%s=%d-%d\r\n"; - } else { - char const* setupFmt = "SETUP %s%s%s RTSP/1.0\r\n"; - unsigned setupSize = strlen(setupFmt) - + strlen(prefix) + strlen (separator) + strlen(suffix); - setupStr = new char[setupSize]; - sprintf(setupStr, setupFmt, prefix, separator, suffix); - - transportFmt = "Transport: RTP/AVP%s%s%s=%d-%d\r\n"; - } - - if (transportStr == NULL) { - // Construct a "Transport:" header. - char const* transportTypeStr; - char const* modeStr = streamOutgoing ? ";mode=receive" : ""; - // Note: I think the above is nonstandard, but DSS wants it this way - char const* portTypeStr; - unsigned short rtpNumber, rtcpNumber; - if (streamUsingTCP) { // streaming over the RTSP connection - transportTypeStr = "/TCP;unicast"; - portTypeStr = ";interleaved"; - rtpNumber = fTCPStreamIdCount++; - rtcpNumber = fTCPStreamIdCount++; - } else { // normal RTP streaming - unsigned connectionAddress = subsession.connectionEndpointAddress(); - Boolean requestMulticastStreaming = IsMulticastAddress(connectionAddress) - || (connectionAddress == 0 && forceMulticastOnUnspecified); - transportTypeStr = requestMulticastStreaming ? ";multicast" : ";unicast"; - portTypeStr = ";client_port"; - rtpNumber = subsession.clientPortNum(); - if (rtpNumber == 0) { - envir().setResultMsg("Client port number unknown\n"); - break; - } - rtcpNumber = rtpNumber + 1; - } - - unsigned transportSize = strlen(transportFmt) - + strlen(transportTypeStr) + strlen(modeStr) + strlen(portTypeStr) + 2*5 /* max port len */; - transportStr = new char[transportSize]; - sprintf(transportStr, transportFmt, - transportTypeStr, modeStr, portTypeStr, rtpNumber, rtcpNumber); - } - - // (Later implement more, as specified in the RTSP spec, sec D.1 #####) - char* const cmdFmt = - "%s" - "CSeq: %d\r\n" - "%s" - "%s" - "%s" - "%s" - "\r\n"; - - unsigned cmdSize = strlen(cmdFmt) - + strlen(setupStr) - + 20 /* max int len */ - + strlen(transportStr) - + strlen(sessionStr) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - setupStr, - ++fCSeq, - transportStr, - sessionStr, - authenticatorStr, - fUserAgentHeaderStr); - delete[] authenticatorStr; - if (sessionStr[0] != '\0') delete[] sessionStr; - delete[] setupStr; delete[] transportStr; - - // And then send it: - if (!sendRequest(cmd, "SETUP")) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("SETUP", bytesRead, responseCode, firstLine, nextLineStart)) break; - - // Look for a "Session:" header (to set our session id), and - // a "Transport: " header (to set the server address/port) - // For now, ignore other headers. - char* lineStart; - char* sessionId = new char[fResponseBufferSize]; // ensures we have enough space - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - - if (sscanf(lineStart, "Session: %[^;]", sessionId) == 1) { - subsession.sessionId = strDup(sessionId); - delete[] fLastSessionId; fLastSessionId = strDup(sessionId); - - // Also look for an optional "; timeout = " parameter following this: - char* afterSessionId - = lineStart + strlen(sessionId) + strlen ("Session: ");; - int timeoutVal; - if (sscanf(afterSessionId, "; timeout = %d", &timeoutVal) == 1) { - fSessionTimeoutParameter = timeoutVal; - } - continue; - } - - char* serverAddressStr; - portNumBits serverPortNum; - unsigned char rtpChannelId, rtcpChannelId; - if (parseTransportResponse(lineStart, - serverAddressStr, serverPortNum, - rtpChannelId, rtcpChannelId)) { - delete[] subsession.connectionEndpointName(); - subsession.connectionEndpointName() = serverAddressStr; - subsession.serverPortNum = serverPortNum; - subsession.rtpChannelId = rtpChannelId; - subsession.rtcpChannelId = rtcpChannelId; - continue; - } - } - delete[] sessionId; - - if (subsession.sessionId == NULL) { - envir().setResultMsg("\"Session:\" header is missing in the response"); - break; - } - - if (streamUsingTCP) { - // Tell the subsession to receive RTP (and send/receive RTCP) - // over the RTSP stream: - if (subsession.rtpSource() != NULL) - subsession.rtpSource()->setStreamSocket(fInputSocketNum, - subsession.rtpChannelId); - if (subsession.rtcpInstance() != NULL) - subsession.rtcpInstance()->setStreamSocket(fInputSocketNum, - subsession.rtcpChannelId); - } else { - // Normal case. - // Set the RTP and RTCP sockets' destination address and port - // from the information in the SETUP response: - subsession.setDestinations(fServerAddress); - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -static char* createScaleString(float scale, float currentScale) { - char buf[100]; - if (scale == 1.0f && currentScale == 1.0f) { - // This is the default value; we don't need a "Scale:" header: - buf[0] = '\0'; - } else { - Locale("POSIX"); - sprintf(buf, "Scale: %f\r\n", scale); - } - - return strDup(buf); -} - -static char* createRangeString(float start, float end) { - char buf[100]; - if (start < 0) { - // We're resuming from a PAUSE; there's no "Range:" header at all - buf[0] = '\0'; - } else if (end < 0) { - // There's no end time: - Locale("POSIX"); - sprintf(buf, "Range: npt=%.3f-\r\n", start); - } else { - // There's both a start and an end time; include them both in the "Range:" hdr - Locale("POSIX"); - sprintf(buf, "Range: npt=%.3f-%.3f\r\n", start, end); - } - - return strDup(buf); -} - -static char const* NoSessionErr = "No RTSP session is currently in progress\n"; - -Boolean RTSPClient::playMediaSession(MediaSession& session, - float start, float end, float scale) { -#ifdef SUPPORT_REAL_RTSP - if (session.isRealNetworksRDT) { - // This is a RealNetworks stream; set the "Subscribe" parameter before proceeding: - char* streamRuleString = RealGetSubscribeRuleString(&session); - setMediaSessionParameter(session, "Subscribe", streamRuleString); - delete[] streamRuleString; - } -#endif - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progress - if (fLastSessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the PLAY command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, "PLAY", fBaseURL); - // And then a "Scale:" string: - char* scaleStr = createScaleString(scale, session.scale()); - // And then a "Range:" string: - char* rangeStr = createRangeString(start, end); - - char* const cmdFmt = - "PLAY %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "%s" - "%s" - "\r\n"; - - unsigned cmdSize = strlen(cmdFmt) - + strlen(fBaseURL) - + 20 /* max int len */ - + strlen(fLastSessionId) - + strlen(scaleStr) - + strlen(rangeStr) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - fBaseURL, - ++fCSeq, - fLastSessionId, - scaleStr, - rangeStr, - authenticatorStr, - fUserAgentHeaderStr); - delete[] scaleStr; - delete[] rangeStr; - delete[] authenticatorStr; - - if (!sendRequest(cmd, "PLAY")) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("PLAY", bytesRead, responseCode, firstLine, nextLineStart)) break; - - // Look for various headers that we understand: - char* lineStart; - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - - if (parseScaleHeader(lineStart, session.scale())) break; - } - - if (fTCPStreamIdCount == 0) { // we're not receiving RTP-over-TCP - // Arrange to handle incoming requests sent by the server - envir().taskScheduler().turnOnBackgroundReadHandling(fInputSocketNum, - (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this); - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient::playMediaSubsession(MediaSubsession& subsession, - float start, float end, float scale, - Boolean hackForDSS) { - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progress - if (subsession.sessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the PLAY command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, "PLAY", fBaseURL); - // And then a "Scale:" string: - char* scaleStr = createScaleString(scale, subsession.scale()); - // And then a "Range:" string: - char* rangeStr = createRangeString(start, end); - - char* const cmdFmt = - "PLAY %s%s%s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "%s" - "%s" - "\r\n"; - - char const *prefix, *separator, *suffix; - constructSubsessionURL(subsession, prefix, separator, suffix); - if (hackForDSS || fServerIsKasenna) { - // When "PLAY" is used to inject RTP packets into a DSS - // (violating the RTSP spec, btw; "RECORD" should have been used) - // the DSS can crash (or hang) if the '/trackid=...' portion of - // the URL is present. - separator = suffix = ""; - } - - unsigned cmdSize = strlen(cmdFmt) - + strlen(prefix) + strlen(separator) + strlen(suffix) - + 20 /* max int len */ - + strlen(subsession.sessionId) - + strlen(scaleStr) - + strlen(rangeStr) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - prefix, separator, suffix, - ++fCSeq, - subsession.sessionId, - scaleStr, - rangeStr, - authenticatorStr, - fUserAgentHeaderStr); - delete[] scaleStr; - delete[] rangeStr; - delete[] authenticatorStr; - - if (!sendRequest(cmd, "PLAY")) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("PLAY", bytesRead, responseCode, firstLine, nextLineStart)) break; - - // Look for various headers that we understand: - char* lineStart; - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - - if (parseRTPInfoHeader(lineStart, - subsession.rtpInfo.trackId, - subsession.rtpInfo.seqNum, - subsession.rtpInfo.timestamp)) { - continue; - } - if (parseScaleHeader(lineStart, subsession.scale())) continue; - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient::pauseMediaSession(MediaSession& session) { - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progress - if (fLastSessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the PAUSE command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, "PAUSE", fBaseURL); - - char* const cmdFmt = - "PAUSE %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "\r\n"; - - unsigned cmdSize = strlen(cmdFmt) - + strlen(fBaseURL) - + 20 /* max int len */ - + strlen(fLastSessionId) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - fBaseURL, - ++fCSeq, - fLastSessionId, - authenticatorStr, - fUserAgentHeaderStr); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "PAUSE")) break; - - if (fTCPStreamIdCount == 0) { // When TCP streaming, don't look for a response - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("PAUSE", bytesRead, responseCode, firstLine, nextLineStart)) break; - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient::pauseMediaSubsession(MediaSubsession& subsession) { - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progress - if (subsession.sessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the PAUSE command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, "PAUSE", fBaseURL); - - char* const cmdFmt = - "PAUSE %s%s%s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "\r\n"; - - char const *prefix, *separator, *suffix; - constructSubsessionURL(subsession, prefix, separator, suffix); - if (fServerIsKasenna) separator = suffix = ""; - - unsigned cmdSize = strlen(cmdFmt) - + strlen(prefix) + strlen(separator) + strlen(suffix) - + 20 /* max int len */ - + strlen(subsession.sessionId) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - prefix, separator, suffix, - ++fCSeq, - subsession.sessionId, - authenticatorStr, - fUserAgentHeaderStr); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "PAUSE")) break; - - if (fTCPStreamIdCount == 0) { // When TCP streaming, don't look for a response - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("PAUSE", bytesRead, responseCode, firstLine, nextLineStart)) break; - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient::recordMediaSubsession(MediaSubsession& subsession) { - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progress - if (subsession.sessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the RECORD command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, - "RECORD", fBaseURL); - - char* const cmdFmt = - "RECORD %s%s%s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "Range: npt=0-\r\n" - "%s" - "%s" - "\r\n"; - - char const *prefix, *separator, *suffix; - constructSubsessionURL(subsession, prefix, separator, suffix); - - unsigned cmdSize = strlen(cmdFmt) - + strlen(prefix) + strlen(separator) + strlen(suffix) - + 20 /* max int len */ - + strlen(subsession.sessionId) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - prefix, separator, suffix, - ++fCSeq, - subsession.sessionId, - authenticatorStr, - fUserAgentHeaderStr); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "RECORD")) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("RECORD", bytesRead, responseCode, firstLine, nextLineStart)) break; - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient::setMediaSessionParameter(MediaSession& /*session*/, - char const* parameterName, - char const* parameterValue) { - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progress - if (fLastSessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the SET_PARAMETER command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, - "SET_PARAMETER", fBaseURL); - - char* const cmdFmt = - "SET_PARAMETER %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "%s: %s\r\n" - "\r\n"; - - unsigned cmdSize = strlen(cmdFmt) - + strlen(fBaseURL) - + 20 /* max int len */ - + strlen(fLastSessionId) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize - + strlen(parameterName) + strlen(parameterValue); - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - fBaseURL, - ++fCSeq, - fLastSessionId, - authenticatorStr, - fUserAgentHeaderStr, - parameterName, parameterValue); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "SET_PARAMETER")) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("SET_PARAMETER", bytesRead, responseCode, firstLine, nextLineStart)) break; - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient::getMediaSessionParameter(MediaSession& /*session*/, - char const* parameterName, - char*& parameterValue) { - parameterValue = NULL; // default result - Boolean const haveParameterName = parameterName != NULL && parameterName[0] != '\0'; - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progress - if (fLastSessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the GET_PARAMETER command: - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, - "GET_PARAMETER", fBaseURL); - - if (haveParameterName) { - char* const cmdFmt = - "GET_PARAMETER %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "Content-type: text/parameters\r\n" - "Content-length: %d\r\n\r\n" - "%s\r\n" - "\r\n"; - - unsigned cmdSize = strlen(cmdFmt) - + strlen(fBaseURL) - + 20 /* max int len */ - + strlen(fLastSessionId) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize - + strlen(parameterName); - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - fBaseURL, - ++fCSeq, - fLastSessionId, - authenticatorStr, - fUserAgentHeaderStr, - strlen(parameterName)+2, - parameterName); - } else { - char* const cmdFmt = - "GET_PARAMETER %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "\r\n"; - - unsigned cmdSize = strlen(cmdFmt) - + strlen(fBaseURL) - + 20 /* max int len */ - + strlen(fLastSessionId) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - fBaseURL, - ++fCSeq, - fLastSessionId, - authenticatorStr, - fUserAgentHeaderStr); - } - delete[] authenticatorStr; - - if (!sendRequest(cmd, "GET_PARAMETER")) break; - - // Get the response from the server: - // This section was copied/modified from the RTSPClient::describeURL func - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("GET_PARAMETER", bytesRead, responseCode, firstLine, - nextLineStart, False /*don't check for response code 200*/)) break; - - // Inspect the first line to check whether it's a result code that - // we can handle. - if (responseCode != 200) { - envir().setResultMsg("cannot handle GET_PARAMETER response: ", firstLine); - break; - } - - // Skip every subsequent header line, until we see a blank line - // The remaining data is assumed to be the parameter data that we want. - char* serverType = new char[fResponseBufferSize]; // ensures enough space - int contentLength = -1; - char* lineStart; - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - if (lineStart[0] == '\0') break; // this is a blank line - - if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1 - || sscanf(lineStart, "Content-length: %d", &contentLength) == 1) { - if (contentLength < 0) { - envir().setResultMsg("Bad \"Content-length:\" header: \"", - lineStart, "\""); - break; - } - } - } - delete[] serverType; - - // We're now at the end of the response header lines - if (lineStart == NULL) { - envir().setResultMsg("no content following header lines: ", - fResponseBuffer); - break; - } - - // Use the remaining data as the parameter data, but first, check - // the "Content-length:" header (if any) that we saw. We may need to - // read more data, or we may have extraneous data in the buffer. - char* bodyStart = nextLineStart; - if (contentLength >= 0) { - // We saw a "Content-length:" header - unsigned numBodyBytes = &firstLine[bytesRead] - bodyStart; - if (contentLength > (int)numBodyBytes) { - // We need to read more data. First, make sure we have enough - // space for it: - unsigned numExtraBytesNeeded = contentLength - numBodyBytes; - unsigned remainingBufferSize - = fResponseBufferSize - (bytesRead + (firstLine - fResponseBuffer)); - if (numExtraBytesNeeded > remainingBufferSize) { - char tmpBuf[200]; - sprintf(tmpBuf, "Read buffer size (%d) is too small for \"Content-length:\" %d (need a buffer size of >= %d bytes\n", - fResponseBufferSize, contentLength, - fResponseBufferSize + numExtraBytesNeeded - remainingBufferSize); - envir().setResultMsg(tmpBuf); - break; - } - - // Keep reading more data until we have enough: - if (fVerbosityLevel >= 1) { - envir() << "Need to read " << numExtraBytesNeeded - << " extra bytes\n"; - } - while (numExtraBytesNeeded > 0) { - struct sockaddr_in fromAddress; - char* ptr = &firstLine[bytesRead]; - int bytesRead2 = readSocket(envir(), fInputSocketNum, (unsigned char*)ptr, - numExtraBytesNeeded, fromAddress); - if (bytesRead2 < 0) break; - ptr[bytesRead2] = '\0'; - if (fVerbosityLevel >= 1) { - envir() << "Read " << bytesRead2 << " extra bytes: " - << ptr << "\n"; - } - - bytesRead += bytesRead2; - numExtraBytesNeeded -= bytesRead2; - } - if (numExtraBytesNeeded > 0) break; // one of the reads failed - } - } - - if (haveParameterName - && !parseGetParameterHeader(bodyStart, parameterName, parameterValue)) break; - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient::teardownMediaSession(MediaSession& session) { - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progreee - if (fLastSessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the TEARDOWN command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, - "TEARDOWN", fBaseURL); - - char* const cmdFmt = - "TEARDOWN %s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "\r\n"; - - unsigned cmdSize = strlen(cmdFmt) - + strlen(fBaseURL) - + 20 /* max int len */ - + strlen(fLastSessionId) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - fBaseURL, - ++fCSeq, - fLastSessionId, - authenticatorStr, - fUserAgentHeaderStr); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "TEARDOWN")) break; - - if (fTCPStreamIdCount == 0) { // When TCP streaming, don't look for a response - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("TEARDOWN", bytesRead, responseCode, firstLine, nextLineStart)) break; - - // Run through each subsession, deleting its "sessionId": - MediaSubsessionIterator iter(session); - MediaSubsession* subsession; - while ((subsession = iter.next()) != NULL) { - delete[] (char*)subsession->sessionId; - subsession->sessionId = NULL; - } - - delete[] fLastSessionId; fLastSessionId = NULL; - // we're done with this session - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient::teardownMediaSubsession(MediaSubsession& subsession) { - char* cmd = NULL; - do { - // First, make sure that we have a RTSP session in progreee - if (subsession.sessionId == NULL) { - envir().setResultMsg(NoSessionErr); - break; - } - - // Send the TEARDOWN command: - - // First, construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(&fCurrentAuthenticator, - "TEARDOWN", fBaseURL); - - char* const cmdFmt = - "TEARDOWN %s%s%s RTSP/1.0\r\n" - "CSeq: %d\r\n" - "Session: %s\r\n" - "%s" - "%s" - "\r\n"; - - char const *prefix, *separator, *suffix; - constructSubsessionURL(subsession, prefix, separator, suffix); - - unsigned cmdSize = strlen(cmdFmt) - + strlen(prefix) + strlen(separator) + strlen(suffix) - + 20 /* max int len */ - + strlen(subsession.sessionId) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - prefix, separator, suffix, - ++fCSeq, - subsession.sessionId, - authenticatorStr, - fUserAgentHeaderStr); - delete[] authenticatorStr; - - if (!sendRequest(cmd, "TEARDOWN")) break; - - if (fTCPStreamIdCount == 0) { // When TCP streaming, don't look for a response - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("TEARDOWN", bytesRead, responseCode, firstLine, nextLineStart)) break; - } - - delete[] (char*)subsession.sessionId; - subsession.sessionId = NULL; - // we're done with this session - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean RTSPClient -::openConnectionFromURL(char const* url, Authenticator* authenticator) { - do { - // Set this as our base URL: - delete[] fBaseURL; fBaseURL = strDup(url); if (fBaseURL == NULL) break; - - // Begin by parsing the URL: - - NetAddress destAddress; - portNumBits urlPortNum; - char const* urlSuffix; - if (!parseRTSPURL(envir(), url, destAddress, urlPortNum, &urlSuffix)) break; - portNumBits destPortNum - = fTunnelOverHTTPPortNum == 0 ? urlPortNum : fTunnelOverHTTPPortNum; - - if (fInputSocketNum < 0) { - // We don't yet have a TCP socket. Set one up (blocking) now: - fInputSocketNum = fOutputSocketNum - = setupStreamSocket(envir(), 0, False /* =>blocking */); - if (fInputSocketNum < 0) break; - - // Connect to the remote endpoint: - fServerAddress = *(unsigned*)(destAddress.data()); - MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(destPortNum)); - if (connect(fInputSocketNum, (struct sockaddr*)&remoteName, sizeof remoteName) - != 0) { - envir().setResultErrMsg("connect() failed: "); - break; - } - - if (fTunnelOverHTTPPortNum != 0 && !setupHTTPTunneling(urlSuffix, authenticator)) break; - } - - return True; - } while (0); - - fDescribeStatusCode = 1; - resetTCPSockets(); - return False; -} - -Boolean RTSPClient::parseRTSPURL(UsageEnvironment& env, char const* url, - NetAddress& address, - portNumBits& portNum, - char const** urlSuffix) { - do { - // Parse the URL as "rtsp://
:/" - // (with ":" and "/" optional) - // Also, skip over any "[:]@" preceding
- char const* prefix = "rtsp://"; - unsigned const prefixLength = 7; - if (_strncasecmp(url, prefix, prefixLength) != 0) { - env.setResultMsg("URL is not of the form \"", prefix, "\""); - break; - } - - unsigned const parseBufferSize = 100; - char parseBuffer[parseBufferSize]; - char const* from = &url[prefixLength]; - - // Skip over any "[:]@" - // (Note that this code fails if contains '@' or '/', but - // given that these characters can also appear in , there seems to - // be no way of unambiguously parsing that situation.) - char const* from1 = from; - while (*from1 != '\0' && *from1 != '/') { - if (*from1 == '@') { - from = ++from1; - break; - } - ++from1; - } - - char* to = &parseBuffer[0]; - unsigned i; - for (i = 0; i < parseBufferSize; ++i) { - if (*from == '\0' || *from == ':' || *from == '/') { - // We've completed parsing the address - *to = '\0'; - break; - } - *to++ = *from++; - } - if (i == parseBufferSize) { - env.setResultMsg("URL is too long"); - break; - } - - NetAddressList addresses(parseBuffer); - if (addresses.numAddresses() == 0) { - env.setResultMsg("Failed to find network address for \"", - parseBuffer, "\""); - break; - } - address = *(addresses.firstAddress()); - - portNum = 554; // default value - char nextChar = *from; - if (nextChar == ':') { - int portNumInt; - if (sscanf(++from, "%d", &portNumInt) != 1) { - env.setResultMsg("No port number follows ':'"); - break; - } - if (portNumInt < 1 || portNumInt > 65535) { - env.setResultMsg("Bad port number"); - break; - } - portNum = (portNumBits)portNumInt; - while (*from >= '0' && *from <= '9') ++from; // skip over port number - } - - // The remainder of the URL is the suffix: - if (urlSuffix != NULL) *urlSuffix = from; - - return True; - } while (0); - - return False; -} - -Boolean RTSPClient::parseRTSPURLUsernamePassword(char const* url, - char*& username, - char*& password) { - username = password = NULL; // by default - do { - // Parse the URL as "rtsp://[:]@" - char const* prefix = "rtsp://"; - unsigned const prefixLength = 7; - if (_strncasecmp(url, prefix, prefixLength) != 0) break; - - // Look for the ':' and '@': - unsigned usernameIndex = prefixLength; - unsigned colonIndex = 0, atIndex = 0; - for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) { - if (url[i] == ':' && colonIndex == 0) { - colonIndex = i; - } else if (url[i] == '@') { - atIndex = i; - break; // we're done - } - } - if (atIndex == 0) break; // no '@' found - - char* urlCopy = strDup(url); - urlCopy[atIndex] = '\0'; - if (colonIndex > 0) { - urlCopy[colonIndex] = '\0'; - password = strDup(&urlCopy[colonIndex+1]); - } else { - password = strDup(""); - } - username = strDup(&urlCopy[usernameIndex]); - delete[] urlCopy; - - return True; - } while (0); - - return False; -} - -char* -RTSPClient::createAuthenticatorString(Authenticator const* authenticator, - char const* cmd, char const* url) { - if (authenticator != NULL && authenticator->realm() != NULL - && authenticator->username() != NULL && authenticator->password() != NULL) { - // We've been provided a filled-in authenticator, so use it: - char* authenticatorStr; - if (authenticator->nonce() != NULL) { // Digest authentication - char* const authFmt = - "Authorization: Digest username=\"%s\", realm=\"%s\", " - "nonce=\"%s\", uri=\"%s\", response=\"%s\"\r\n"; - char const* response = authenticator->computeDigestResponse(cmd, url); - unsigned authBufSize = strlen(authFmt) - + strlen(authenticator->username()) + strlen(authenticator->realm()) - + strlen(authenticator->nonce()) + strlen(url) + strlen(response); - authenticatorStr = new char[authBufSize]; - sprintf(authenticatorStr, authFmt, - authenticator->username(), authenticator->realm(), - authenticator->nonce(), url, response); - authenticator->reclaimDigestResponse(response); - } else { // Basic authentication - char* const authFmt = "Authorization: Basic %s\r\n"; - char* usernamePassword - = new char[strlen(authenticator->username()) - + strlen(authenticator->password()) + 2]; - sprintf(usernamePassword, "%s:%s", - authenticator->username(), authenticator->password()); - char* response = base64Encode(usernamePassword); - unsigned authBufSize = strlen(authFmt) + strlen(response); - authenticatorStr = new char[authBufSize]; - sprintf(authenticatorStr, authFmt, response); - delete[] response; delete[] usernamePassword; - } - - return authenticatorStr; - } - - return strDup(""); -} - -void RTSPClient::checkForAuthenticationFailure(unsigned responseCode, - char*& nextLineStart, - Authenticator* authenticator) { - if (responseCode == 401 && authenticator != NULL) { - // We have an authentication failure, so fill in "authenticator" - // using the contents of a following "WWW-Authenticate:" line. - // (Once we compute a 'response' for "authenticator", it can be - // used in a subsequent request - that will hopefully succeed.) - char* lineStart; - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - if (lineStart[0] == '\0') break; // this is a blank line - - char* realm = strDupSize(lineStart); - char* nonce = strDupSize(lineStart); - Boolean foundAuthenticateHeader = False; - if (sscanf(lineStart, "WWW-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", - realm, nonce) == 2) { - authenticator->setRealmAndNonce(realm, nonce); - foundAuthenticateHeader = True; - } else if (sscanf(lineStart, "WWW-Authenticate: Basic realm=\"%[^\"]\"", - realm) == 1) { - authenticator->setRealmAndNonce(realm, NULL); // Basic authentication - foundAuthenticateHeader = True; - } - delete[] realm; delete[] nonce; - if (foundAuthenticateHeader) break; - } - } -} - -Boolean RTSPClient::sendRequest(char const* requestString, char const* tag, - Boolean base64EncodeIfOverHTTP) { - if (fVerbosityLevel >= 1) { - envir() << "Sending request: " << requestString << "\n"; - } - - char* newRequestString = NULL; - if (fTunnelOverHTTPPortNum != 0 && base64EncodeIfOverHTTP) { - requestString = newRequestString = base64Encode(requestString); - if (fVerbosityLevel >= 1) { - envir() << "\tThe request was base-64 encoded to: " << requestString << "\n\n"; - } - } - - Boolean result - = send(fOutputSocketNum, requestString, strlen(requestString), 0) >= 0; - delete[] newRequestString; - - if (!result) { - if (tag == NULL) tag = ""; - char const* errFmt = "%s send() failed: "; - unsigned const errLength = strlen(errFmt) + strlen(tag); - char* err = new char[errLength]; - sprintf(err, errFmt, tag); - envir().setResultErrMsg(err); - delete[] err; - } - return result; -} - -Boolean RTSPClient::getResponse(char const* tag, - unsigned& bytesRead, unsigned& responseCode, - char*& firstLine, char*& nextLineStart, - Boolean checkFor200Response) { - do { - char* readBuf = fResponseBuffer; - bytesRead = getResponse1(readBuf, fResponseBufferSize); - if (bytesRead == 0) { - envir().setResultErrMsg("Failed to read response: "); - break; - } - if (fVerbosityLevel >= 1) { - envir() << "Received " << tag << " response: " << readBuf << "\n"; - } - - firstLine = readBuf; - nextLineStart = getLine(firstLine); - if (!parseResponseCode(firstLine, responseCode)) break; - - - if (responseCode != 200 && checkFor200Response) { - envir().setResultMsg(tag, ": cannot handle response: ", firstLine); - break; - } - - return True; - } while (0); - - // An error occurred: - return False; -} - -unsigned RTSPClient::getResponse1(char*& responseBuffer, - unsigned responseBufferSize) { - struct sockaddr_in fromAddress; - - if (responseBufferSize == 0) return 0; // just in case... - responseBuffer[0] = '\0'; // ditto - - // Begin by reading and checking the first byte of the response. - // If it's '$', then there's an interleaved RTP (or RTCP)-over-TCP - // packet here. We need to read and discard it first. - Boolean success = False; - while (1) { - unsigned char firstByte; - if (readSocket(envir(), fInputSocketNum, &firstByte, 1, fromAddress) - != 1) break; - if (firstByte != '$') { - // Normal case: This is the start of a regular response; use it: - responseBuffer[0] = firstByte; - success = True; - break; - } else { - // This is an interleaved packet; read and discard it: - unsigned char streamChannelId; - if (readSocket(envir(), fInputSocketNum, &streamChannelId, 1, fromAddress) - != 1) break; - - unsigned short size; - if (readSocketExact(envir(), fInputSocketNum, (unsigned char*)&size, 2, - fromAddress) != 2) break; - size = ntohs(size); - if (fVerbosityLevel >= 1) { - envir() << "Discarding interleaved RTP or RTCP packet (" - << size << " bytes, channel id " - << streamChannelId << ")\n"; - } - - unsigned char* tmpBuffer = new unsigned char[size]; - if (tmpBuffer == NULL) break; - unsigned bytesRead = 0; - unsigned bytesToRead = size; - unsigned curBytesRead; - while ((curBytesRead = readSocket(envir(), fInputSocketNum, - &tmpBuffer[bytesRead], bytesToRead, - fromAddress)) > 0) { - bytesRead += curBytesRead; - if (bytesRead >= size) break; - bytesToRead -= curBytesRead; - } - delete[] tmpBuffer; - if (bytesRead != size) break; - - success = True; - } - } - if (!success) return 0; - - // Keep reading data from the socket until we see "\r\n\r\n" (except - // at the start), or until we fill up our buffer. - // Don't read any more than this. - char* p = responseBuffer; - Boolean haveSeenNonCRLF = False; - int bytesRead = 1; // because we've already read the first byte - while (bytesRead < (int)responseBufferSize) { - int bytesReadNow - = readSocket(envir(), fInputSocketNum, - (unsigned char*)(responseBuffer+bytesRead), - 1, fromAddress); - if (bytesReadNow <= 0) { - envir().setResultMsg("RTSP response was truncated"); - break; - } - bytesRead += bytesReadNow; - - // Check whether we have "\r\n\r\n": - char* lastToCheck = responseBuffer+bytesRead-4; - if (lastToCheck < responseBuffer) continue; - for (; p <= lastToCheck; ++p) { - if (haveSeenNonCRLF) { - if (*p == '\r' && *(p+1) == '\n' && - *(p+2) == '\r' && *(p+3) == '\n') { - responseBuffer[bytesRead] = '\0'; - - // Before returning, trim any \r or \n from the start: - while (*responseBuffer == '\r' || *responseBuffer == '\n') { - ++responseBuffer; - --bytesRead; - } - return bytesRead; - } - } else { - if (*p != '\r' && *p != '\n') { - haveSeenNonCRLF = True; - } - } - } - } - - envir().setResultMsg("We received a response not ending with "); - return 0; -} - -Boolean RTSPClient::parseResponseCode(char const* line, - unsigned& responseCode) { - if (sscanf(line, "%*s%u", &responseCode) != 1) { - envir().setResultMsg("no response code in line: \"", line, "\""); - return False; - } - - return True; -} - -Boolean RTSPClient::parseTransportResponse(char const* line, - char*& serverAddressStr, - portNumBits& serverPortNum, - unsigned char& rtpChannelId, - unsigned char& rtcpChannelId) { - // Initialize the return parameters to 'not found' values: - serverAddressStr = NULL; - serverPortNum = 0; - rtpChannelId = rtcpChannelId = 0xFF; - - char* foundServerAddressStr = NULL; - Boolean foundServerPortNum = False; - Boolean foundChannelIds = False; - unsigned rtpCid, rtcpCid; - Boolean isMulticast = True; // by default - char* foundDestinationStr = NULL; - portNumBits multicastPortNumRTP, multicastPortNumRTCP; - Boolean foundMulticastPortNum = False; - - // First, check for "Transport:" - if (_strncasecmp(line, "Transport: ", 11) != 0) return False; - line += 11; - - // Then, run through each of the fields, looking for ones we handle: - char const* fields = line; - char* field = strDupSize(fields); - while (sscanf(fields, "%[^;]", field) == 1) { - if (sscanf(field, "server_port=%hu", &serverPortNum) == 1) { - foundServerPortNum = True; - } else if (_strncasecmp(field, "source=", 7) == 0) { - delete[] foundServerAddressStr; - foundServerAddressStr = strDup(field+7); - } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) { - rtpChannelId = (unsigned char)rtpCid; - rtcpChannelId = (unsigned char)rtcpCid; - foundChannelIds = True; - } else if (strcmp(field, "unicast") == 0) { - isMulticast = False; - } else if (_strncasecmp(field, "destination=", 12) == 0) { - delete[] foundDestinationStr; - foundDestinationStr = strDup(field+12); - } else if (sscanf(field, "port=%hu-%hu", - &multicastPortNumRTP, &multicastPortNumRTCP) == 2) { - foundMulticastPortNum = True; - } - - fields += strlen(field); - while (fields[0] == ';') ++fields; // skip over all leading ';' chars - if (fields[0] == '\0') break; - } - delete[] field; - - // If we're multicast, and have a "destination=" (multicast) address, then use this - // as the 'server' address (because some weird servers don't specify the multicast - // address earlier, in the "DESCRIBE" response's SDP: - if (isMulticast && foundDestinationStr != NULL && foundMulticastPortNum) { - delete[] foundServerAddressStr; - serverAddressStr = foundDestinationStr; - serverPortNum = multicastPortNumRTP; - return True; - } - delete[] foundDestinationStr; - - if (foundServerPortNum || foundChannelIds) { - serverAddressStr = foundServerAddressStr; - return True; - } - - delete[] foundServerAddressStr; - return False; -} - -Boolean RTSPClient::parseRTPInfoHeader(char const* line, - unsigned& trackId, - u_int16_t& seqNum, - u_int32_t& timestamp) { - if (_strncasecmp(line, "RTP-Info: ", 10) != 0) return False; - line += 10; - char const* fields = line; - char* field = strDupSize(fields); - - while (sscanf(fields, "%[^;]", field) == 1) { - if (sscanf(field, "url=trackID=%u", &trackId) == 1 || - sscanf(field, "url=trackid=%u", &trackId) == 1 || - sscanf(field, "seq=%hu", &seqNum) == 1 || - sscanf(field, "rtptime=%u", ×tamp) == 1) { - } - - fields += strlen(field); - if (fields[0] == '\0') break; - ++fields; // skip over the ';' - } - - delete[] field; - return True; -} - -Boolean RTSPClient::parseScaleHeader(char const* line, float& scale) { - if (_strncasecmp(line, "Scale: ", 7) != 0) return False; - line += 7; - - Locale("POSIX"); - return sscanf(line, "%f", &scale) == 1; -} - -Boolean RTSPClient::parseGetParameterHeader(char const* line, - const char* param, - char*& value) { - if ((param != NULL && param[0] != '\0') && - (line != NULL && line[0] != '\0')) { - int param_len = strlen(param); - int line_len = strlen(line); - - if (_strncasecmp(line, param, param_len) != 0) { - if (fVerbosityLevel >= 1) { - envir() << "Parsing for \""<< param << "\" and didn't find it, return False\n"; - } - return False; - } - - // Strip \r\n from the end if it's there. - if (line[line_len-2] == '\r' && line[line_len-1] == '\n') { - line_len -= 2; - } - - // Look for ": " appended to our requested parameter - if (line[param_len] == ':' && line[param_len+1] == ' ') { - // But make sure ": " wasn't in our actual serach param before adjusting - if (param[param_len-2] != ':' && param[param_len-1] != ' ') { - if (fVerbosityLevel >= 1) { - envir() << "Found \": \" appended to parameter\n"; - } - param_len += 2; - } - } - - // Get the string we want out of the line: - value = strDup(line+param_len); - return True; - } - return False; -} - -Boolean RTSPClient::setupHTTPTunneling(char const* urlSuffix, - Authenticator* authenticator) { - if (fVerbosityLevel >= 1) { - envir() << "Requesting RTSP-over-HTTP tunneling (on port " - << fTunnelOverHTTPPortNum << ")\n\n"; - } - if (urlSuffix == NULL || urlSuffix[0] == '\0') urlSuffix = "/"; - char* cmd = NULL; - - do { - // Create a 'session cookie' string, using MD5: - struct { - struct timeval timestamp; - unsigned counter; - } seedData; - gettimeofday(&seedData.timestamp, NULL); - static unsigned counter = 0; - seedData.counter = ++counter; - char sessionCookie[33]; - our_MD5Data((unsigned char*)(&seedData), sizeof seedData, sessionCookie); - // DSS seems to require that the 'session cookie' string be 22 bytes long: - sessionCookie[23] = '\0'; - - // Construct an authenticator string: - char* authenticatorStr - = createAuthenticatorString(authenticator, "GET", urlSuffix); - - // Begin by sending a HTTP "GET", to set up the server->client link: - char* const getCmdFmt = - "GET %s HTTP/1.0\r\n" - "%s" - "%s" - "x-sessioncookie: %s\r\n" - "Accept: application/x-rtsp-tunnelled\r\n" - "Pragma: no-cache\r\n" - "Cache-Control: no-cache\r\n" - "\r\n"; - unsigned cmdSize = strlen(getCmdFmt) - + strlen(urlSuffix) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize - + strlen(sessionCookie); - cmd = new char[cmdSize]; - sprintf(cmd, getCmdFmt, - urlSuffix, - authenticatorStr, - fUserAgentHeaderStr, - sessionCookie); - delete[] authenticatorStr; - if (!sendRequest(cmd, "HTTP GET", False/*don't base64-encode*/)) break; - - // Get the response from the server: - unsigned bytesRead; unsigned responseCode; - char* firstLine; char* nextLineStart; - if (!getResponse("HTTP GET", bytesRead, responseCode, firstLine, nextLineStart, - False /*don't check for response code 200*/)) break; - if (responseCode != 200) { - checkForAuthenticationFailure(responseCode, nextLineStart, authenticator); - envir().setResultMsg("cannot handle HTTP GET response: ", firstLine); - break; - } - - // Next, set up a second TCP connection (to the same server & port as before) - // for the HTTP-tunneled client->server link. All future output will be to - // this socket. - fOutputSocketNum = setupStreamSocket(envir(), 0, False /* =>blocking */); - if (fOutputSocketNum < 0) break; - - // Connect to the remote endpoint: - MAKE_SOCKADDR_IN(remoteName, fServerAddress, htons(fTunnelOverHTTPPortNum)); - if (connect(fOutputSocketNum, - (struct sockaddr*)&remoteName, sizeof remoteName) != 0) { - envir().setResultErrMsg("connect() failed: "); - break; - } - - // Then, send a HTTP "POST", to set up the client->server link: - authenticatorStr = createAuthenticatorString(authenticator, "POST", urlSuffix); - char* const postCmdFmt = - "POST %s HTTP/1.0\r\n" - "%s" - "%s" - "x-sessioncookie: %s\r\n" - "Content-Type: application/x-rtsp-tunnelled\r\n" - "Pragma: no-cache\r\n" - "Cache-Control: no-cache\r\n" - "Content-Length: 32767\r\n" - "Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n" - "\r\n"; - cmdSize = strlen(postCmdFmt) - + strlen(urlSuffix) - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize - + strlen(sessionCookie); - delete[] cmd; cmd = new char[cmdSize]; - sprintf(cmd, postCmdFmt, - urlSuffix, - authenticatorStr, - fUserAgentHeaderStr, - sessionCookie); - delete[] authenticatorStr; - if (!sendRequest(cmd, "HTTP POST", False/*don't base64-encode*/)) break; - - // Note that there's no response to the "POST". - - delete[] cmd; - return True; - } while (0); - - // An error occurred: - delete[] cmd; - return False; -} - -void RTSPClient::incomingRequestHandler(void* instance, int /*mask*/) { - RTSPClient* session = (RTSPClient*)instance; - session->incomingRequestHandler1(); -} - -void RTSPClient::incomingRequestHandler1() { - unsigned bytesRead; - char* readBuf = fResponseBuffer; - bytesRead = getResponse1(readBuf, fResponseBufferSize); - if (bytesRead == 0) { - envir().setResultErrMsg("Failed to read response: "); - return; - } - // Parse the request string into command name and 'CSeq', - // then handle the command: - char cmdName[RTSP_PARAM_STRING_MAX]; - char urlPreSuffix[RTSP_PARAM_STRING_MAX]; - char urlSuffix[RTSP_PARAM_STRING_MAX]; - char cseq[RTSP_PARAM_STRING_MAX]; - if (!parseRTSPRequestString((char*)readBuf, bytesRead, - cmdName, sizeof cmdName, - urlPreSuffix, sizeof urlPreSuffix, - urlSuffix, sizeof urlSuffix, - cseq, sizeof cseq)) { - return; - } else { - if (fVerbosityLevel >= 1) { - envir() << "Received request: " << readBuf << "\n"; - } - handleCmd_notSupported(cseq); - } -} - -void RTSPClient::handleCmd_notSupported(char const* cseq) { - char tmpBuf[512]; - snprintf((char*)tmpBuf, sizeof tmpBuf, - "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n\r\n", cseq); - send(fOutputSocketNum, tmpBuf, strlen(tmpBuf), 0); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/RTSPCommon.cpp b/mythtv/libs/libmythlivemedia/liveMedia/RTSPCommon.cpp deleted file mode 100644 index 0b3734ff61d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/RTSPCommon.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Common routines used by both RTSP clients and servers -// Implementation - -#include "RTSPCommon.hh" - -Boolean parseRTSPRequestString(char const* reqStr, - unsigned reqStrSize, - char* resultCmdName, - unsigned resultCmdNameMaxSize, - char* resultURLPreSuffix, - unsigned resultURLPreSuffixMaxSize, - char* resultURLSuffix, - unsigned resultURLSuffixMaxSize, - char* resultCSeq, - unsigned resultCSeqMaxSize) { - // This parser is currently rather dumb; it should be made smarter ##### - - // Read everything up to the first space as the command name: - Boolean parseSucceeded = False; - unsigned i; - for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) { - char c = reqStr[i]; - if (c == ' ' || c == '\t') { - parseSucceeded = True; - break; - } - - resultCmdName[i] = c; - } - resultCmdName[i] = '\0'; - if (!parseSucceeded) return False; - - // Skip over the prefix of any "rtsp://" or "rtsp:/" URL that follows: - unsigned j = i+1; - while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space - for (j = i+1; (int)j < (int)(reqStrSize-8); ++j) { - if ((reqStr[j] == 'r' || reqStr[j] == 'R') - && (reqStr[j+1] == 't' || reqStr[j+1] == 'T') - && (reqStr[j+2] == 's' || reqStr[j+2] == 'S') - && (reqStr[j+3] == 'p' || reqStr[j+3] == 'P') - && reqStr[j+4] == ':' && reqStr[j+5] == '/') { - j += 6; - if (reqStr[j] == '/') { - // This is a "rtsp://" URL; skip over the host:port part that follows: - ++j; - while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ') ++j; - } else { - // This is a "rtsp:/" URL; back up to the "/": - --j; - } - i = j; - break; - } - } - - // Look for the URL suffix (before the following "RTSP/"): - parseSucceeded = False; - for (unsigned k = i+1; (int)k < (int)(reqStrSize-5); ++k) { - if (reqStr[k] == 'R' && reqStr[k+1] == 'T' && - reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/') { - while (--k >= i && reqStr[k] == ' ') {} // go back over all spaces before "RTSP/" - unsigned k1 = k; - while (k1 > i && reqStr[k1] != '/' && reqStr[k1] != ' ') --k1; - // the URL suffix comes from [k1+1,k] - - // Copy "resultURLSuffix": - if (k - k1 + 1 > resultURLSuffixMaxSize) return False; // there's no room - unsigned n = 0, k2 = k1+1; - while (k2 <= k) resultURLSuffix[n++] = reqStr[k2++]; - resultURLSuffix[n] = '\0'; - - // Also look for the URL 'pre-suffix' before this: - unsigned k3 = --k1; - while (k3 > i && reqStr[k3] != '/' && reqStr[k3] != ' ') --k3; - // the URL pre-suffix comes from [k3+1,k1] - - // Copy "resultURLPreSuffix": - if (k1 - k3 + 1 > resultURLPreSuffixMaxSize) return False; // there's no room - n = 0; k2 = k3+1; - while (k2 <= k1) resultURLPreSuffix[n++] = reqStr[k2++]; - resultURLPreSuffix[n] = '\0'; - - i = k + 7; // to go past " RTSP/" - parseSucceeded = True; - break; - } - } - if (!parseSucceeded) return False; - - // Look for "CSeq:", skip whitespace, - // then read everything up to the next \r or \n as 'CSeq': - parseSucceeded = False; - for (j = i; (int)j < (int)(reqStrSize-5); ++j) { - if (reqStr[j] == 'C' && reqStr[j+1] == 'S' && reqStr[j+2] == 'e' && - reqStr[j+3] == 'q' && reqStr[j+4] == ':') { - j += 5; - unsigned n; - while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; - for (n = 0; n < resultCSeqMaxSize-1 && j < reqStrSize; ++n,++j) { - char c = reqStr[j]; - if (c == '\r' || c == '\n') { - parseSucceeded = True; - break; - } - - resultCSeq[n] = c; - } - resultCSeq[n] = '\0'; - break; - } - } - if (!parseSucceeded) return False; - - return True; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/RTSPServer.cpp b/mythtv/libs/libmythlivemedia/liveMedia/RTSPServer.cpp deleted file mode 100644 index 4b4766b78d3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/RTSPServer.cpp +++ /dev/null @@ -1,1214 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A RTSP server -// Implementation - -#include "RTSPServer.hh" -#include "RTSPCommon.hh" -#include - -#if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4) -#else -#include -#define USE_SIGNALS 1 -#endif -#include // for "strftime()" and "gmtime()" - -#define RTPINFO_INCLUDE_RTPTIME 1 - -////////// RTSPServer ////////// - -RTSPServer* -RTSPServer::createNew(UsageEnvironment& env, Port ourPort, - UserAuthenticationDatabase* authDatabase, - unsigned reclamationTestSeconds) { - int ourSocket = -1; - - do { - int ourSocket = setUpOurSocket(env, ourPort); - if (ourSocket == -1) break; - - return new RTSPServer(env, ourSocket, ourPort, authDatabase, - reclamationTestSeconds); - } while (0); - - if (ourSocket != -1) ::closeSocket(ourSocket); - return NULL; -} - -Boolean RTSPServer::lookupByName(UsageEnvironment& env, - char const* name, - RTSPServer*& resultServer) { - resultServer = NULL; // unless we succeed - - Medium* medium; - if (!Medium::lookupByName(env, name, medium)) return False; - - if (!medium->isRTSPServer()) { - env.setResultMsg(name, " is not a RTSP server"); - return False; - } - - resultServer = (RTSPServer*)medium; - return True; -} - -void RTSPServer::addServerMediaSession(ServerMediaSession* serverMediaSession) { - if (serverMediaSession == NULL) return; - - char const* sessionName = serverMediaSession->streamName(); - if (sessionName == NULL) sessionName = ""; - ServerMediaSession* existingSession - = (ServerMediaSession*) - (fServerMediaSessions->Add(sessionName, - (void*)serverMediaSession)); - removeServerMediaSession(existingSession); // if any -} - -ServerMediaSession* RTSPServer::lookupServerMediaSession(char const* streamName) { - return (ServerMediaSession*)(fServerMediaSessions->Lookup(streamName)); -} - -void RTSPServer::removeServerMediaSession(ServerMediaSession* serverMediaSession) { - if (serverMediaSession == NULL) return; - - fServerMediaSessions->Remove(serverMediaSession->streamName()); - if (serverMediaSession->referenceCount() == 0) { - Medium::close(serverMediaSession); - } else { - serverMediaSession->deleteWhenUnreferenced() = True; - } -} - -void RTSPServer::removeServerMediaSession(char const* streamName) { - removeServerMediaSession(lookupServerMediaSession(streamName)); -} - -char* RTSPServer -::rtspURL(ServerMediaSession const* serverMediaSession) const { - struct in_addr ourAddress; - ourAddress.s_addr = ReceivingInterfaceAddr != 0 - ? ReceivingInterfaceAddr - : ourSourceAddressForMulticast(envir()); // hack - - char const* sessionName = serverMediaSession->streamName(); - unsigned sessionNameLength = strlen(sessionName); - - char* urlBuffer = new char[100 + sessionNameLength]; - char* resultURL; - - portNumBits portNumHostOrder = ntohs(fServerPort.num()); - if (portNumHostOrder == 554 /* the default port number */) { - sprintf(urlBuffer, "rtsp://%s/%s", our_inet_ntoa(ourAddress), - sessionName); - } else { - sprintf(urlBuffer, "rtsp://%s:%hu/%s", - our_inet_ntoa(ourAddress), portNumHostOrder, - sessionName); - } - - resultURL = strDup(urlBuffer); - delete[] urlBuffer; - return resultURL; -} - -#define LISTEN_BACKLOG_SIZE 20 - -int RTSPServer::setUpOurSocket(UsageEnvironment& env, Port& ourPort) { - int ourSocket = -1; - - do { - ourSocket = setupStreamSocket(env, ourPort); - if (ourSocket < 0) break; - - // Make sure we have a big send buffer: - if (!increaseSendBufferTo(env, ourSocket, 50*1024)) break; - - // Allow multiple simultaneous connections: - if (listen(ourSocket, LISTEN_BACKLOG_SIZE) < 0) { - env.setResultErrMsg("listen() failed: "); - break; - } - - if (ourPort.num() == 0) { - // bind() will have chosen a port for us; return it also: - if (!getSourcePort(env, ourSocket, ourPort)) break; - } - - return ourSocket; - } while (0); - - if (ourSocket != -1) ::closeSocket(ourSocket); - return -1; -} - -RTSPServer::RTSPServer(UsageEnvironment& env, - int ourSocket, Port ourPort, - UserAuthenticationDatabase* authDatabase, - unsigned reclamationTestSeconds) - : Medium(env), - fServerSocket(ourSocket), fServerPort(ourPort), - fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds), - fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)), - fSessionIdCounter(0) { -#ifdef USE_SIGNALS - // Ignore the SIGPIPE signal, so that clients on the same host that are killed - // don't also kill us: - signal(SIGPIPE, SIG_IGN); -#endif - - // Arrange to handle connections from others: - env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, - (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandler, - this); -} - -RTSPServer::~RTSPServer() { - // Turn off background read handling: - envir().taskScheduler().turnOffBackgroundReadHandling(fServerSocket); - - ::closeSocket(fServerSocket); - - // Remove all server media sessions (they'll get deleted when they're finished): - while (1) { - ServerMediaSession* serverMediaSession - = (ServerMediaSession*)fServerMediaSessions->RemoveNext(); - if (serverMediaSession == NULL) break; - removeServerMediaSession(serverMediaSession); - } - - // Finally, delete the session table itself: - delete fServerMediaSessions; -} - -Boolean RTSPServer::isRTSPServer() const { - return True; -} - -void RTSPServer::incomingConnectionHandler(void* instance, int /*mask*/) { - RTSPServer* server = (RTSPServer*)instance; - server->incomingConnectionHandler1(); -} - -void RTSPServer::incomingConnectionHandler1() { - struct sockaddr_in clientAddr; - SOCKLEN_T clientAddrLen = sizeof clientAddr; - int clientSocket = accept(fServerSocket, (struct sockaddr*)&clientAddr, - &clientAddrLen); - if (clientSocket < 0) { - int err = envir().getErrno(); - if (err != EWOULDBLOCK) { - envir().setResultErrMsg("accept() failed: "); - } - return; - } -#if defined(DEBUG) || defined(DEBUG_CONNECTIONS) - fprintf(stderr, "accept()ed connection from %s\n", our_inet_ntoa(clientAddr.sin_addr)); -#endif - - // Create a new object for this RTSP session: - new RTSPClientSession(*this, ++fSessionIdCounter, - clientSocket, clientAddr); -} - - -////////// RTSPServer::RTSPClientSession ////////// - -RTSPServer::RTSPClientSession -::RTSPClientSession(RTSPServer& ourServer, unsigned sessionId, - int clientSocket, struct sockaddr_in clientAddr) - : fOurServer(ourServer), fOurSessionId(sessionId), - fOurServerMediaSession(NULL), - fClientSocket(clientSocket), fClientAddr(clientAddr), - fLivenessCheckTask(NULL), - fIsMulticast(False), fSessionIsActive(True), fStreamAfterSETUP(False), - fTCPStreamIdCount(0), fNumStreamStates(0), fStreamStates(NULL) { - // Arrange to handle incoming requests: - envir().taskScheduler().turnOnBackgroundReadHandling(fClientSocket, - (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this); - noteLiveness(); -} - -RTSPServer::RTSPClientSession::~RTSPClientSession() { - // Turn off any liveness checking: - envir().taskScheduler().unscheduleDelayedTask(fLivenessCheckTask); - - // Turn off background read handling: - envir().taskScheduler().turnOffBackgroundReadHandling(fClientSocket); - - ::closeSocket(fClientSocket); - - reclaimStreamStates(); - - if (fOurServerMediaSession != NULL) { - fOurServerMediaSession->decrementReferenceCount(); - if (fOurServerMediaSession->referenceCount() == 0 - && fOurServerMediaSession->deleteWhenUnreferenced()) { - fOurServer.removeServerMediaSession(fOurServerMediaSession); - } - } -} - -void RTSPServer::RTSPClientSession::reclaimStreamStates() { - for (unsigned i = 0; i < fNumStreamStates; ++i) { - if (fStreamStates[i].subsession != NULL) { - fStreamStates[i].subsession->deleteStream(fOurSessionId, - fStreamStates[i].streamToken); - } - } - delete[] fStreamStates; fStreamStates = NULL; - fNumStreamStates = 0; -} - -void RTSPServer::RTSPClientSession -::incomingRequestHandler(void* instance, int /*mask*/) { - RTSPClientSession* session = (RTSPClientSession*)instance; - session->incomingRequestHandler1(); -} - -void RTSPServer::RTSPClientSession::incomingRequestHandler1() { - noteLiveness(); - - struct sockaddr_in dummy; // 'from' address, meaningless in this case - int bytesLeft = sizeof fBuffer; - int totalBytes = 0; - Boolean endOfMsg = False; - unsigned char* ptr = fBuffer; - unsigned char* lastCRLF = ptr-3; - - while (!endOfMsg) { - if (bytesLeft <= 0) { - // command too big - delete this; - return; - } - - int bytesRead = readSocket(envir(), fClientSocket, - ptr, bytesLeft, dummy); - if (bytesRead <= 0) { - // The client socket has apparently died - kill it: - delete this; - return; - } -#ifdef DEBUG - ptr[bytesRead] = '\0'; - fprintf(stderr, "RTSPClientSession[%p]::incomingRequestHandler1() read %d bytes:%s\n", this, bytesRead, ptr); -#endif - - // Look for the end of the message: - unsigned char *tmpPtr = ptr; - if (totalBytes > 0) --tmpPtr; // In case the last read ended with a - while (tmpPtr < &ptr[bytesRead-1]) { - if (*tmpPtr == '\r' && *(tmpPtr+1) == '\n') { - if (tmpPtr - lastCRLF == 2) { // This is it: - endOfMsg = 1; - break; - } - lastCRLF = tmpPtr; - } - ++tmpPtr; - } - - bytesLeft -= bytesRead; - totalBytes += bytesRead; - ptr += bytesRead; - } - fBuffer[totalBytes] = '\0'; - - // Parse the request string into command name and 'CSeq', - // then handle the command: - char cmdName[RTSP_PARAM_STRING_MAX]; - char urlPreSuffix[RTSP_PARAM_STRING_MAX]; - char urlSuffix[RTSP_PARAM_STRING_MAX]; - char cseq[RTSP_PARAM_STRING_MAX]; - if (!parseRTSPRequestString((char*)fBuffer, totalBytes, - cmdName, sizeof cmdName, - urlPreSuffix, sizeof urlPreSuffix, - urlSuffix, sizeof urlSuffix, - cseq, sizeof cseq)) { -#ifdef DEBUG - fprintf(stderr, "parseRTSPRequestString() failed!\n"); -#endif - handleCmd_bad(cseq); - } else { -#ifdef DEBUG - fprintf(stderr, "parseRTSPRequestString() returned cmdName \"%s\", urlPreSuffix \"%s\", urlSuffix \"%s\"\n", cmdName, urlPreSuffix, urlSuffix); -#endif - if (strcmp(cmdName, "OPTIONS") == 0) { - handleCmd_OPTIONS(cseq); - } else if (strcmp(cmdName, "DESCRIBE") == 0) { - handleCmd_DESCRIBE(cseq, urlSuffix, (char const*)fBuffer); - } else if (strcmp(cmdName, "SETUP") == 0) { - handleCmd_SETUP(cseq, urlPreSuffix, urlSuffix, (char const*)fBuffer); - } else if (strcmp(cmdName, "TEARDOWN") == 0 - || strcmp(cmdName, "PLAY") == 0 - || strcmp(cmdName, "PAUSE") == 0 - || strcmp(cmdName, "GET_PARAMETER") == 0) { - handleCmd_withinSession(cmdName, urlPreSuffix, urlSuffix, cseq, - (char const*)fBuffer); - } else { - handleCmd_notSupported(cseq); - } - } - -#ifdef DEBUG - fprintf(stderr, "sending response: %s", fResponseBuffer); -#endif - send(fClientSocket, (char const*)fResponseBuffer, strlen((char*)fResponseBuffer), 0); - - if (strcmp(cmdName, "SETUP") == 0 && fStreamAfterSETUP) { - // The client has asked for streaming to commence now, rather than after a - // subsequent "PLAY" command. So, simulate the effect of a "PLAY" command: - handleCmd_withinSession("PLAY", urlPreSuffix, urlSuffix, cseq, - (char const*)fBuffer); - } - if (!fSessionIsActive) delete this; -} - -// Handler routines for specific RTSP commands: - -// Generate a "Date:" header for use in a RTSP response: -static char const* dateHeader() { - static char buf[200]; -#if !defined(_WIN32_WCE) - time_t tt = time(NULL); - strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt)); -#else - // WinCE apparently doesn't have "time()", "strftime()", or "gmtime()", - // so generate the "Date:" header a different, WinCE-specific way. - // (Thanks to Pierre l'Hussiez for this code) - SYSTEMTIME SystemTime; - GetSystemTime(&SystemTime); - WCHAR dateFormat[] = L"ddd, MMM dd yyyy"; - WCHAR timeFormat[] = L"HH:mm:ss GMT\r\n"; - WCHAR inBuf[200]; - DWORD locale = LOCALE_NEUTRAL; - - int ret = GetDateFormat(locale, 0, &SystemTime, - (LPTSTR)dateFormat, (LPTSTR)inBuf, sizeof inBuf); - inBuf[ret - 1] = ' '; - ret = GetTimeFormat(locale, 0, &SystemTime, - (LPTSTR)timeFormat, - (LPTSTR)inBuf + ret, (sizeof inBuf) - ret); - wcstombs(buf, inBuf, wcslen(inBuf)); -#endif - return buf; -} - -static char const* allowedCommandNames - = "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE"; - -void RTSPServer::RTSPClientSession::handleCmd_bad(char const* /*cseq*/) { - // Don't do anything with "cseq", because it might be nonsense - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 400 Bad Request\r\n%sAllow: %s\r\n\r\n", - dateHeader(), allowedCommandNames); - fSessionIsActive = False; // triggers deletion of ourself after responding -} - -void RTSPServer::RTSPClientSession::handleCmd_notSupported(char const* cseq) { - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n%sAllow: %s\r\n\r\n", - cseq, dateHeader(), allowedCommandNames); - fSessionIsActive = False; // triggers deletion of ourself after responding -} - -void RTSPServer::RTSPClientSession::handleCmd_notFound(char const* cseq) { - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 404 Stream Not Found\r\nCSeq: %s\r\n%s\r\n", - cseq, dateHeader()); - fSessionIsActive = False; // triggers deletion of ourself after responding -} - -void RTSPServer::RTSPClientSession::handleCmd_unsupportedTransport(char const* cseq) { - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 461 Unsupported Transport\r\nCSeq: %s\r\n%s\r\n", - cseq, dateHeader()); - fSessionIsActive = False; // triggers deletion of ourself after responding -} - -void RTSPServer::RTSPClientSession::handleCmd_OPTIONS(char const* cseq) { - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n", - cseq, dateHeader(), allowedCommandNames); -} - -void RTSPServer::RTSPClientSession -::handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix, - char const* fullRequestStr) { - char* sdpDescription = NULL; - char* rtspURL = NULL; - do { - if (!authenticationOK("DESCRIBE", cseq, fullRequestStr)) break; - - // We should really check that the request contains an "Accept:" ##### - // for "application/sdp", because that's what we're sending back ##### - - // Begin by looking up the "ServerMediaSession" object for the - // specified "urlSuffix": - ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix); - if (session == NULL) { - handleCmd_notFound(cseq); - break; - } - - // Then, assemble a SDP description for this session: - sdpDescription = session->generateSDPDescription(); - if (sdpDescription == NULL) { - // This usually means that a file name that was specified for a - // "ServerMediaSubsession" does not exist. - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n" - "CSeq: %s\r\n" - "%s\r\n", - cseq, - dateHeader()); - break; - } - unsigned sdpDescriptionSize = strlen(sdpDescription); - - // Also, generate our RTSP URL, for the "Content-Base:" header - // (which is necessary to ensure that the correct URL gets used in - // subsequent "SETUP" requests). - rtspURL = fOurServer.rtspURL(session); - - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\nCSeq: %s\r\n" - "%s" - "Content-Base: %s/\r\n" - "Content-Type: application/sdp\r\n" - "Content-Length: %d\r\n\r\n" - "%s", - cseq, - dateHeader(), - rtspURL, - sdpDescriptionSize, - sdpDescription); - } while (0); - - delete[] sdpDescription; - delete[] rtspURL; -} - -typedef enum StreamingMode { - RTP_UDP, - RTP_TCP, - RAW_UDP -}; - -static void parseTransportHeader(char const* buf, - StreamingMode& streamingMode, - char*& streamingModeString, - char*& destinationAddressStr, - u_int8_t& destinationTTL, - portNumBits& clientRTPPortNum, // if UDP - portNumBits& clientRTCPPortNum, // if UDP - unsigned char& rtpChannelId, // if TCP - unsigned char& rtcpChannelId // if TCP - ) { - // Initialize the result parameters to default values: - streamingMode = RTP_UDP; - streamingModeString = NULL; - destinationAddressStr = NULL; - destinationTTL = 255; - clientRTPPortNum = 0; - clientRTCPPortNum = 1; - rtpChannelId = rtcpChannelId = 0xFF; - - portNumBits p1, p2; - unsigned ttl, rtpCid, rtcpCid; - - // First, find "Transport:" - while (1) { - if (*buf == '\0') return; // not found - if (_strncasecmp(buf, "Transport: ", 11) == 0) break; - ++buf; - } - - // Then, run through each of the fields, looking for ones we handle: - char const* fields = buf + 11; - char* field = strDupSize(fields); - while (sscanf(fields, "%[^;]", field) == 1) { - if (strcmp(field, "RTP/AVP/TCP") == 0) { - streamingMode = RTP_TCP; - } else if (strcmp(field, "RAW/RAW/UDP") == 0 || - strcmp(field, "MP2T/H2221/UDP") == 0) { - streamingMode = RAW_UDP; - streamingModeString = strDup(field); - } else if (_strncasecmp(field, "destination=", 12) == 0) { - delete[] destinationAddressStr; - destinationAddressStr = strDup(field+12); - } else if (sscanf(field, "ttl%u", &ttl) == 1) { - destinationTTL = (u_int8_t)ttl; - } else if (sscanf(field, "client_port=%hu-%hu", &p1, &p2) == 2) { - clientRTPPortNum = p1; - clientRTCPPortNum = p2; - } else if (sscanf(field, "client_port=%hu", &p1) == 1) { - clientRTPPortNum = p1; - clientRTCPPortNum = streamingMode == RAW_UDP ? 0 : p1 + 1; - } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) { - rtpChannelId = (unsigned char)rtpCid; - rtcpChannelId = (unsigned char)rtcpCid; - } - - fields += strlen(field); - while (*fields == ';') ++fields; // skip over separating ';' chars - if (*fields == '\0' || *fields == '\r' || *fields == '\n') break; - } - delete[] field; -} - -static Boolean parseRangeHeader(char const* buf, float& rangeStart, float& rangeEnd) { - // Initialize the result parameters to default values: - rangeStart = rangeEnd = 0.0; - - // First, find "Range:" - while (1) { - if (*buf == '\0') return False; // not found - if (_strncasecmp(buf, "Range: ", 7) == 0) break; - ++buf; - } - - // Then, run through each of the fields, looking for ones we handle: - char const* fields = buf + 7; - while (*fields == ' ') ++fields; - float start, end; - if (sscanf(fields, "npt = %f - %f", &start, &end) == 2) { - rangeStart = start; - rangeEnd = end; - } else if (sscanf(fields, "npt = %f -", &start) == 1) { - rangeStart = start; - } else { - return False; // The header is malformed - } - - return True; -} - -void RTSPServer::RTSPClientSession -::handleCmd_SETUP(char const* cseq, - char const* urlPreSuffix, char const* urlSuffix, - char const* fullRequestStr) { - // "urlPreSuffix" should be the session (stream) name, and - // "urlSuffix" should be the subsession (track) name. - char const* streamName = urlPreSuffix; - char const* trackId = urlSuffix; - - // Check whether we have existing session state, and, if so, whether it's - // for the session that's named in "streamName". (Note that we don't - // support more than one concurrent session on the same client connection.) ##### - if (fOurServerMediaSession != NULL - && strcmp(streamName, fOurServerMediaSession->streamName()) != 0) { - fOurServerMediaSession = NULL; - } - if (fOurServerMediaSession == NULL) { - // Set up this session's state. - - // Look up the "ServerMediaSession" object for the specified stream: - if (streamName[0] != '\0' || - fOurServer.lookupServerMediaSession("") != NULL) { // normal case - } else { // weird case: there was no track id in the URL - streamName = urlSuffix; - trackId = NULL; - } - fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName); - if (fOurServerMediaSession == NULL) { - handleCmd_notFound(cseq); - return; - } - - fOurServerMediaSession->incrementReferenceCount(); - - // Set up our array of states for this session's subsessions (tracks): - reclaimStreamStates(); - ServerMediaSubsessionIterator iter(*fOurServerMediaSession); - for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {} - fStreamStates = new struct streamState[fNumStreamStates]; - iter.reset(); - ServerMediaSubsession* subsession; - for (unsigned i = 0; i < fNumStreamStates; ++i) { - subsession = iter.next(); - fStreamStates[i].subsession = subsession; - fStreamStates[i].streamToken = NULL; // for now; reset by SETUP later - } - } - - // Look up information for the specified subsession (track): - ServerMediaSubsession* subsession = NULL; - unsigned streamNum; - if (trackId != NULL && trackId[0] != '\0') { // normal case - for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) { - subsession = fStreamStates[streamNum].subsession; - if (subsession != NULL && strcmp(trackId, subsession->trackId()) == 0) break; - } - if (streamNum >= fNumStreamStates) { - // The specified track id doesn't exist, so this request fails: - handleCmd_notFound(cseq); - return; - } - } else { - // Weird case: there was no track id in the URL. - // This works only if we have only one subsession: - if (fNumStreamStates != 1) { - handleCmd_bad(cseq); - return; - } - streamNum = 0; - subsession = fStreamStates[streamNum].subsession; - } - // ASSERT: subsession != NULL - - // Look for a "Transport:" header in the request string, - // to extract client parameters: - StreamingMode streamingMode; - char* streamingModeString; // set when RAW_UDP streaming is specified - char* clientsDestinationAddressStr; - u_int8_t clientsDestinationTTL; - portNumBits clientRTPPortNum, clientRTCPPortNum; - unsigned char rtpChannelId, rtcpChannelId; - parseTransportHeader(fullRequestStr, streamingMode, streamingModeString, - clientsDestinationAddressStr, clientsDestinationTTL, - clientRTPPortNum, clientRTCPPortNum, - rtpChannelId, rtcpChannelId); - if (streamingMode == RTP_TCP && rtpChannelId == 0xFF) { - // TCP streaming was requested, but with no "interleaving=" fields. - // (QuickTime Player sometimes does this.) Set the RTP and RTCP channel ids to - // proper values: - rtpChannelId = fTCPStreamIdCount; rtcpChannelId = fTCPStreamIdCount+1; - } - fTCPStreamIdCount += 2; - - Port clientRTPPort(clientRTPPortNum); - Port clientRTCPPort(clientRTCPPortNum); - - // Next, check whether a "Range:" header is present in the request. - // This isn't legal, but some clients do this to combine "SETUP" and "PLAY": - float rangeStart, rangeEnd; - fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd); - - // Then, get server parameters from the 'subsession': - int tcpSocketNum = streamingMode == RTP_TCP ? fClientSocket : -1; - netAddressBits destinationAddress = 0; - u_int8_t destinationTTL = 255; -#ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING - if (clientsDestinationAddressStr != NULL) { - // Use the client-provided "destination" address. - // Note: This potentially allows the server to be used in denial-of-service - // attacks, so don't enable this code unless you're sure that clients are - // trusted. - destinationAddress = our_inet_addr(clientsDestinationAddressStr); - } - // Also use the client-provided TTL. - destinationTTL = clientsDestinationTTL; -#endif - delete[] clientsDestinationAddressStr; - Port serverRTPPort(0); - Port serverRTCPPort(0); - subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr, - clientRTPPort, clientRTCPPort, - tcpSocketNum, rtpChannelId, rtcpChannelId, - destinationAddress, destinationTTL, fIsMulticast, - serverRTPPort, serverRTCPPort, - fStreamStates[streamNum].streamToken); - struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress; - if (fIsMulticast) { - if (streamingMode == RTP_TCP) { - // multicast streams can't be sent via TCP - handleCmd_unsupportedTransport(cseq); - return; - } - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\n" - "CSeq: %s\r\n" - "%s" - "Transport: RTP/AVP;multicast;destination=%s;port=%d-%d;ttl=%d\r\n" - "Session: %d\r\n\r\n", - cseq, - dateHeader(), - our_inet_ntoa(destinationAddr), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), destinationTTL, - fOurSessionId); - } else { - switch (streamingMode) { - case RTP_UDP: { - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\n" - "CSeq: %s\r\n" - "%s" - "Transport: RTP/AVP;unicast;destination=%s;client_port=%d-%d;server_port=%d-%d\r\n" - "Session: %d\r\n\r\n", - cseq, - dateHeader(), - our_inet_ntoa(destinationAddr), ntohs(clientRTPPort.num()), ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()), - fOurSessionId); - break; - } - case RTP_TCP: { - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\n" - "CSeq: %s\r\n" - "%s" - "Transport: RTP/AVP/TCP;unicast;destination=%s;interleaved=%d-%d\r\n" - "Session: %d\r\n\r\n", - cseq, - dateHeader(), - our_inet_ntoa(destinationAddr), rtpChannelId, rtcpChannelId, - fOurSessionId); - break; - } - case RAW_UDP: { - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\n" - "CSeq: %s\r\n" - "%s" - "Transport: %s;unicast;destination=%s;client_port=%d;server_port=%d\r\n" - "Session: %d\r\n\r\n", - cseq, - dateHeader(), - streamingModeString, our_inet_ntoa(destinationAddr), ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()), - fOurSessionId); - delete[] streamingModeString; - break; - } - } - } -} - -void RTSPServer::RTSPClientSession -::handleCmd_withinSession(char const* cmdName, - char const* urlPreSuffix, char const* urlSuffix, - char const* cseq, char const* fullRequestStr) { - // This will either be: - // - a non-aggregated operation, if "urlPreSuffix" is the session (stream) - // name and "urlSuffix" is the subsession (track) name, or - // - a aggregated operation, if "urlSuffix" is the session (stream) name, - // or "urlPreSuffix" is the session (stream) name, and "urlSuffix" - // is empty. - // First, figure out which of these it is: - if (fOurServerMediaSession == NULL) { // There wasn't a previous SETUP! - handleCmd_notSupported(cseq); - return; - } - ServerMediaSubsession* subsession; - if (urlSuffix[0] != '\0' && - strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) { - // Non-aggregated operation. - // Look up the media subsession whose track id is "urlSuffix": - ServerMediaSubsessionIterator iter(*fOurServerMediaSession); - while ((subsession = iter.next()) != NULL) { - if (strcmp(subsession->trackId(), urlSuffix) == 0) break; // success - } - if (subsession == NULL) { // no such track! - handleCmd_notFound(cseq); - return; - } - } else if (strcmp(fOurServerMediaSession->streamName(), urlSuffix) == 0 || - strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) { - // Aggregated operation - subsession = NULL; - } else { // the request doesn't match a known stream and/or track at all! - handleCmd_notFound(cseq); - return; - } - - if (strcmp(cmdName, "TEARDOWN") == 0) { - handleCmd_TEARDOWN(subsession, cseq); - } else if (strcmp(cmdName, "PLAY") == 0) { - handleCmd_PLAY(subsession, cseq, fullRequestStr); - } else if (strcmp(cmdName, "PAUSE") == 0) { - handleCmd_PAUSE(subsession, cseq); - } else if (strcmp(cmdName, "GET_PARAMETER") == 0) { - handleCmd_GET_PARAMETER(subsession, cseq, fullRequestStr); - } -} - -void RTSPServer::RTSPClientSession -::handleCmd_TEARDOWN(ServerMediaSubsession* /*subsession*/, char const* cseq) { - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%s\r\n", - cseq, dateHeader()); - fSessionIsActive = False; // triggers deletion of ourself after responding -} - -static Boolean parseScaleHeader(char const* buf, float& scale) { - // Initialize the result parameter to a default value: - scale = 1.0; - - // First, find "Scale:" - while (1) { - if (*buf == '\0') return False; // not found - if (_strncasecmp(buf, "Scale: ", 7) == 0) break; - ++buf; - } - - // Then, run through each of the fields, looking for ones we handle: - char const* fields = buf + 7; - while (*fields == ' ') ++fields; - float sc; - if (sscanf(fields, "%f", &sc) == 1) { - scale = sc; - } else { - return False; // The header is malformed - } - - return True; -} - -void RTSPServer::RTSPClientSession - ::handleCmd_PLAY(ServerMediaSubsession* subsession, char const* cseq, - char const* fullRequestStr) { - char* rtspURL = fOurServer.rtspURL(fOurServerMediaSession); - unsigned rtspURLSize = strlen(rtspURL); - - //// Parse the client's "Scale:" header, if any: - float scale; - Boolean sawScaleHeader = parseScaleHeader(fullRequestStr, scale); - - // Try to set the stream's scale factor to this value: - if (subsession == NULL /*aggregate op*/) { - fOurServerMediaSession->testScaleFactor(scale); - } else { - subsession->testScaleFactor(scale); - } - - char buf[100]; - char* scaleHeader; - if (!sawScaleHeader) { - buf[0] = '\0'; // Because we didn't see a Scale: header, don't send one back - } else { - sprintf(buf, "Scale: %f\r\n", scale); - } - scaleHeader = strDup(buf); - - //// Parse the client's "Range:" header, if any: - float rangeStart, rangeEnd; - Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd); - - // Use this information, plus the stream's duration (if known), to create - // our own "Range:" header, for the response: - float duration = subsession == NULL /*aggregate op*/ - ? fOurServerMediaSession->duration() : subsession->duration(); - if (duration < 0.0) { - // We're an aggregate PLAY, but the subsessions have different durations. - // Use the largest of these durations in our header - duration = -duration; - } - - if (rangeEnd < 0.0 || rangeEnd > duration) rangeEnd = duration; - if (rangeStart < 0.0) { - rangeStart = 0.0; - } else if (rangeEnd > 0.0 && scale > 0.0 && rangeStart > rangeEnd) { - rangeStart = rangeEnd; - } - - char* rangeHeader; - if (!sawRangeHeader) { - buf[0] = '\0'; // Because we didn't see a Range: header, don't send one back - } else if (rangeEnd == 0.0 && scale >= 0.0) { - sprintf(buf, "Range: npt=%.3f-\r\n", rangeStart); - } else { - sprintf(buf, "Range: npt=%.3f-%.3f\r\n", rangeStart, rangeEnd); - } - rangeHeader = strDup(buf); - - // Create a "RTP-Info:" line. It will get filled in from each subsession's state: - char const* rtpInfoFmt = - "%s" // "RTP-Info:", plus any preceding rtpInfo items - "%s" // comma separator, if needed - "url=%s/%s" - ";seq=%d" -#ifdef RTPINFO_INCLUDE_RTPTIME - ";rtptime=%u" -#endif - ; - unsigned rtpInfoFmtSize = strlen(rtpInfoFmt); - char* rtpInfo = strDup("RTP-Info: "); - unsigned i, numRTPInfoItems = 0; - - // Do any required seeking/scaling on each subsession, before starting streaming: - for (i = 0; i < fNumStreamStates; ++i) { - if (subsession == NULL /* means: aggregated operation */ - || subsession == fStreamStates[i].subsession) { - if (sawScaleHeader) { - fStreamStates[i].subsession->setStreamScale(fOurSessionId, - fStreamStates[i].streamToken, - scale); - } - if (sawRangeHeader) { - fStreamStates[i].subsession->seekStream(fOurSessionId, - fStreamStates[i].streamToken, - rangeStart); - } - } - } - - // Now, start streaming: - for (i = 0; i < fNumStreamStates; ++i) { - if (subsession == NULL /* means: aggregated operation */ - || subsession == fStreamStates[i].subsession) { - unsigned short rtpSeqNum = 0; - unsigned rtpTimestamp = 0; - fStreamStates[i].subsession->startStream(fOurSessionId, - fStreamStates[i].streamToken, - (TaskFunc*)noteClientLiveness, - this, - rtpSeqNum, rtpTimestamp); - const char *urlSuffix = fStreamStates[i].subsession->trackId(); - char* prevRTPInfo = rtpInfo; - unsigned rtpInfoSize = rtpInfoFmtSize - + strlen(prevRTPInfo) - + 1 - + rtspURLSize + strlen(urlSuffix) - + 5 /*max unsigned short len*/ -#ifdef RTPINFO_INCLUDE_RTPTIME - + 10 /*max unsigned (32-bit) len*/ -#endif - + 2 /*allows for trailing \r\n at final end of string*/; - rtpInfo = new char[rtpInfoSize]; - sprintf(rtpInfo, rtpInfoFmt, - prevRTPInfo, - numRTPInfoItems++ == 0 ? "" : ",", - rtspURL, urlSuffix, - rtpSeqNum -#ifdef RTPINFO_INCLUDE_RTPTIME - ,rtpTimestamp -#endif - ); - delete[] prevRTPInfo; - } - } - if (numRTPInfoItems == 0) { - rtpInfo[0] = '\0'; - } else { - unsigned rtpInfoLen = strlen(rtpInfo); - rtpInfo[rtpInfoLen] = '\r'; - rtpInfo[rtpInfoLen+1] = '\n'; - rtpInfo[rtpInfoLen+2] = '\0'; - } - - // Fill in the response: - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\n" - "CSeq: %s\r\n" - "%s" - "%s" - "%s" - "Session: %d\r\n" - "%s\r\n", - cseq, - dateHeader(), - scaleHeader, - rangeHeader, - fOurSessionId, - rtpInfo); - delete[] rtpInfo; delete[] rangeHeader; - delete[] scaleHeader; delete[] rtspURL; -} - -void RTSPServer::RTSPClientSession - ::handleCmd_PAUSE(ServerMediaSubsession* subsession, char const* cseq) { - for (unsigned i = 0; i < fNumStreamStates; ++i) { - if (subsession == NULL /* means: aggregated operation */ - || subsession == fStreamStates[i].subsession) { - fStreamStates[i].subsession->pauseStream(fOurSessionId, - fStreamStates[i].streamToken); - } - } - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n", - cseq, dateHeader(), fOurSessionId); -} - -void RTSPServer::RTSPClientSession -::handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession, char const* cseq, - char const* /*fullRequestStr*/) { - // We implement "GET_PARAMETER" just as a 'keep alive', - // and send back an empty response: - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n", - cseq, dateHeader(), fOurSessionId); -} - -static Boolean parseAuthorizationHeader(char const* buf, - char const*& username, - char const*& realm, - char const*& nonce, char const*& uri, - char const*& response) { - // Initialize the result parameters to default values: - username = realm = nonce = uri = response = NULL; - - // First, find "Authorization:" - while (1) { - if (*buf == '\0') return False; // not found - if (_strncasecmp(buf, "Authorization: Digest ", 22) == 0) break; - ++buf; - } - - // Then, run through each of the fields, looking for ones we handle: - char const* fields = buf + 22; - while (*fields == ' ') ++fields; - char* parameter = strDupSize(fields); - char* value = strDupSize(fields); - while (1) { - value[0] = '\0'; - if (sscanf(fields, "%[^=]=\"%[^\"]\"", parameter, value) != 2 && - sscanf(fields, "%[^=]=\"\"", parameter) != 1) { - break; - } - if (strcmp(parameter, "username") == 0) { - username = strDup(value); - } else if (strcmp(parameter, "realm") == 0) { - realm = strDup(value); - } else if (strcmp(parameter, "nonce") == 0) { - nonce = strDup(value); - } else if (strcmp(parameter, "uri") == 0) { - uri = strDup(value); - } else if (strcmp(parameter, "response") == 0) { - response = strDup(value); - } - - fields += strlen(parameter) + 2 /*="*/ + strlen(value) + 1 /*"*/; - while (*fields == ',' || *fields == ' ') ++fields; - // skip over any separating ',' and ' ' chars - if (*fields == '\0' || *fields == '\r' || *fields == '\n') break; - } - delete[] parameter; delete[] value; - return True; -} - -Boolean RTSPServer::RTSPClientSession -::authenticationOK(char const* cmdName, char const* cseq, - char const* fullRequestStr) { - // If we weren't set up with an authentication database, we're OK: - if (fOurServer.fAuthDB == NULL) return True; - - char const* username = NULL; char const* realm = NULL; char const* nonce = NULL; - char const* uri = NULL; char const* response = NULL; - Boolean success = False; - - do { - // To authenticate, we first need to have a nonce set up - // from a previous attempt: - if (fCurrentAuthenticator.nonce() == NULL) break; - - // Next, the request needs to contain an "Authorization:" header, - // containing a username, (our) realm, (our) nonce, uri, - // and response string: - if (!parseAuthorizationHeader(fullRequestStr, - username, realm, nonce, uri, response) - || username == NULL - || realm == NULL || strcmp(realm, fCurrentAuthenticator.realm()) != 0 - || nonce == NULL || strcmp(nonce, fCurrentAuthenticator.nonce()) != 0 - || uri == NULL || response == NULL) { - break; - } - - // Next, the username has to be known to us: - char const* password = fOurServer.fAuthDB->lookupPassword(username); -#ifdef DEBUG - fprintf(stderr, "lookupPassword(%s) returned password %s\n", username, password); -#endif - if (password == NULL) break; - fCurrentAuthenticator. - setUsernameAndPassword(username, password, - fOurServer.fAuthDB->passwordsAreMD5()); - - // Finally, compute a digest response from the information that we have, - // and compare it to the one that we were given: - char const* ourResponse - = fCurrentAuthenticator.computeDigestResponse(cmdName, uri); - success = (strcmp(ourResponse, response) == 0); - fCurrentAuthenticator.reclaimDigestResponse(ourResponse); - } while (0); - - delete[] (char*)username; delete[] (char*)realm; delete[] (char*)nonce; - delete[] (char*)uri; delete[] (char*)response; - if (success) return True; - - // If we get here, there was some kind of authentication failure. - // Send back a "401 Unauthorized" response, with a new random nonce: - fCurrentAuthenticator.setRealmAndRandomNonce(fOurServer.fAuthDB->realm()); - snprintf((char*)fResponseBuffer, sizeof fResponseBuffer, - "RTSP/1.0 401 Unauthorized\r\n" - "CSeq: %s\r\n" - "%s" - "WWW-Authenticate: Digest realm=\"%s\", nonce=\"%s\"\r\n\r\n", - cseq, - dateHeader(), - fCurrentAuthenticator.realm(), fCurrentAuthenticator.nonce()); - return False; -} - -void RTSPServer::RTSPClientSession::noteLiveness() { - if (fOurServer.fReclamationTestSeconds > 0) { - envir().taskScheduler() - .rescheduleDelayedTask(fLivenessCheckTask, - fOurServer.fReclamationTestSeconds*1000000, - (TaskFunc*)livenessTimeoutTask, this); - } -} - -void RTSPServer::RTSPClientSession -::noteClientLiveness(RTSPClientSession* clientSession) { - clientSession->noteLiveness(); -} - -void RTSPServer::RTSPClientSession -::livenessTimeoutTask(RTSPClientSession* clientSession) { - // If this gets called, the client session is assumed to have timed out, - // so delete it: - - // However, we don't timeout multicast sessions, because to do so would require - // closing all client sessions that have requested the stream - not just this one. - // Also, the multicast stream itself would usually not be halted, in any case. - if (clientSession->isMulticast()) return; - -#ifdef DEBUG - fprintf(stderr, "RTSP client session from %s has timed out (due to inactivity)\n", our_inet_ntoa(clientSession->fClientAddr.sin_addr)); -#endif - delete clientSession; -} - - -////////// UserAuthenticationDatabase implementation ////////// - -UserAuthenticationDatabase::UserAuthenticationDatabase(char const* realm, - Boolean passwordsAreMD5) - : fTable(HashTable::create(STRING_HASH_KEYS)), - fRealm(strDup(realm == NULL ? "LIVE555 Streaming Media" : realm)), - fPasswordsAreMD5(passwordsAreMD5) { -} - -UserAuthenticationDatabase::~UserAuthenticationDatabase() { - delete[] fRealm; - delete fTable; -} - -void UserAuthenticationDatabase::addUserRecord(char const* username, - char const* password) { - fTable->Add(username, (void*)(strDup(password))); -} - -void UserAuthenticationDatabase::removeUserRecord(char const* username) { - char* password = (char*)(fTable->Lookup(username)); - fTable->Remove(username); - delete[] password; -} - -char const* UserAuthenticationDatabase::lookupPassword(char const* username) { - return (char const*)(fTable->Lookup(username)); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/SIPClient.cpp b/mythtv/libs/libmythlivemedia/liveMedia/SIPClient.cpp deleted file mode 100644 index 6a285e3111b..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/SIPClient.cpp +++ /dev/null @@ -1,947 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A generic SIP client -// Implementation - -#include "SIPClient.hh" -#include "GroupsockHelper.hh" - -#if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4) -#define _strncasecmp _strnicmp -#else -#define _strncasecmp strncasecmp -#endif - -////////// SIPClient ////////// - -SIPClient* SIPClient -::createNew(UsageEnvironment& env, - unsigned char desiredAudioRTPPayloadFormat, - char const* mimeSubtype, - int verbosityLevel, char const* applicationName) { - return new SIPClient(env, desiredAudioRTPPayloadFormat, mimeSubtype, - verbosityLevel, applicationName); -} - -SIPClient::SIPClient(UsageEnvironment& env, - unsigned char desiredAudioRTPPayloadFormat, - char const* mimeSubtype, - int verbosityLevel, char const* applicationName) - : Medium(env), - fT1(500000 /* 500 ms */), - fDesiredAudioRTPPayloadFormat(desiredAudioRTPPayloadFormat), - fVerbosityLevel(verbosityLevel), - fCSeq(0), fURL(NULL), fURLSize(0), - fToTagStr(NULL), fToTagStrSize(0), - fUserName(NULL), fUserNameSize(0), - fInviteSDPDescription(NULL), fInviteCmd(NULL), fInviteCmdSize(0){ - if (mimeSubtype == NULL) mimeSubtype = ""; - fMIMESubtype = strDup(mimeSubtype); - fMIMESubtypeSize = strlen(fMIMESubtype); - - if (applicationName == NULL) applicationName = ""; - fApplicationName = strDup(applicationName); - fApplicationNameSize = strlen(fApplicationName); - - struct in_addr ourAddress; - ourAddress.s_addr = ourSourceAddressForMulticast(env); // hack - fOurAddressStr = strDup(our_inet_ntoa(ourAddress)); - fOurAddressStrSize = strlen(fOurAddressStr); - - fOurSocket = new Groupsock(env, ourAddress, 0, 255); - if (fOurSocket == NULL) { - env << "ERROR: Failed to create socket for addr " - << our_inet_ntoa(ourAddress) << ": " - << env.getResultMsg() << "\n"; - } - - // Now, find out our source port number. Hack: Do this by first trying to - // send a 0-length packet, so that the "getSourcePort()" call will work. - fOurSocket->output(envir(), 255, (unsigned char*)"", 0); - Port srcPort(0); - getSourcePort(env, fOurSocket->socketNum(), srcPort); - if (srcPort.num() != 0) { - fOurPortNum = ntohs(srcPort.num()); - } else { - // No luck. Try again using a default port number: - fOurPortNum = 5060; - delete fOurSocket; - fOurSocket = new Groupsock(env, ourAddress, fOurPortNum, 255); - if (fOurSocket == NULL) { - env << "ERROR: Failed to create socket for addr " - << our_inet_ntoa(ourAddress) << ", port " - << fOurPortNum << ": " - << env.getResultMsg() << "\n"; - } - } - - // Set various headers to be used in each request: - char const* formatStr; - unsigned headerSize; - - // Set the "User-Agent:" header: - char const* const libName = "LIVE555 Streaming Media v"; - char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; - char const* libPrefix; char const* libSuffix; - if (applicationName == NULL || applicationName[0] == '\0') { - applicationName = libPrefix = libSuffix = ""; - } else { - libPrefix = " ("; - libSuffix = ")"; - } - formatStr = "User-Agent: %s%s%s%s%s\r\n"; - headerSize - = strlen(formatStr) + fApplicationNameSize + strlen(libPrefix) - + strlen(libName) + strlen(libVersionStr) + strlen(libSuffix); - fUserAgentHeaderStr = new char[headerSize]; - sprintf(fUserAgentHeaderStr, formatStr, - applicationName, libPrefix, libName, libVersionStr, libSuffix); - fUserAgentHeaderStrSize = strlen(fUserAgentHeaderStr); - - reset(); -} - -SIPClient::~SIPClient() { - reset(); - - delete[] fUserAgentHeaderStr; - delete fOurSocket; - delete[] (char*)fOurAddressStr; - delete[] (char*)fApplicationName; - delete[] (char*)fMIMESubtype; -} - -void SIPClient::reset() { - fWorkingAuthenticator = NULL; - delete[] fInviteCmd; fInviteCmd = NULL; fInviteCmdSize = 0; - delete[] fInviteSDPDescription; fInviteSDPDescription = NULL; - - delete[] (char*)fUserName; fUserName = strDup(fApplicationName); - fUserNameSize = strlen(fUserName); - - fValidAuthenticator.reset(); - - delete[] (char*)fToTagStr; fToTagStr = NULL; fToTagStrSize = 0; - fServerPortNum = 0; - fServerAddress.s_addr = 0; - delete[] (char*)fURL; fURL = NULL; fURLSize = 0; -} - -void SIPClient::setProxyServer(unsigned proxyServerAddress, - portNumBits proxyServerPortNum) { - fServerAddress.s_addr = proxyServerAddress; - fServerPortNum = proxyServerPortNum; - if (fOurSocket != NULL) { - fOurSocket->changeDestinationParameters(fServerAddress, - fServerPortNum, 255); - } -} - -static char* getLine(char* startOfLine) { - // returns the start of the next line, or NULL if none - for (char* ptr = startOfLine; *ptr != '\0'; ++ptr) { - if (*ptr == '\r' || *ptr == '\n') { - // We found the end of the line - *ptr++ = '\0'; - if (*ptr == '\n') ++ptr; - return ptr; - } - } - - return NULL; -} - -char* SIPClient::invite(char const* url, Authenticator* authenticator) { - // First, check whether "url" contains a username:password to be used: - fInviteStatusCode = 0; - char* username; char* password; - if (authenticator == NULL - && parseSIPURLUsernamePassword(url, username, password)) { - char* result = inviteWithPassword(url, username, password); - delete[] username; delete[] password; // they were dynamically allocated - return result; - } - - if (!processURL(url)) return NULL; - - delete[] (char*)fURL; fURL = strDup(url); - fURLSize = strlen(fURL); - - fCallId = our_random(); - fFromTag = our_random(); - - return invite1(authenticator); -} - -char* SIPClient::invite1(Authenticator* authenticator) { - do { - // Send the INVITE command: - - // First, construct an authenticator string: - fValidAuthenticator.reset(); - fWorkingAuthenticator = authenticator; - char* authenticatorStr - = createAuthenticatorString(fWorkingAuthenticator, "INVITE", fURL); - - // Then, construct the SDP description to be sent in the INVITE: - char* rtpmapLine; - unsigned rtpmapLineSize; - if (fMIMESubtypeSize > 0) { - char* const rtpmapFmt = - "a=rtpmap:%u %s/8000\r\n"; - unsigned rtpmapFmtSize = strlen(rtpmapFmt) - + 3 /* max char len */ + fMIMESubtypeSize; - rtpmapLine = new char[rtpmapFmtSize]; - sprintf(rtpmapLine, rtpmapFmt, - fDesiredAudioRTPPayloadFormat, fMIMESubtype); - rtpmapLineSize = strlen(rtpmapLine); - } else { - // Static payload type => no "a=rtpmap:" line - rtpmapLine = strDup(""); - rtpmapLineSize = 0; - } - char* const inviteSDPFmt = - "v=0\r\n" - "o=- %u %u IN IP4 %s\r\n" - "s=%s session\r\n" - "c=IN IP4 %s\r\n" - "t=0 0\r\n" - "m=audio %u RTP/AVP %u\r\n" - "%s"; - unsigned inviteSDPFmtSize = strlen(inviteSDPFmt) - + 20 /* max int len */ + 20 + fOurAddressStrSize - + fApplicationNameSize - + fOurAddressStrSize - + 5 /* max short len */ + 3 /* max char len */ - + rtpmapLineSize; - delete[] fInviteSDPDescription; - fInviteSDPDescription = new char[inviteSDPFmtSize]; - sprintf(fInviteSDPDescription, inviteSDPFmt, - fCallId, fCSeq, fOurAddressStr, - fApplicationName, - fOurAddressStr, - fClientStartPortNum, fDesiredAudioRTPPayloadFormat, - rtpmapLine); - unsigned inviteSDPSize = strlen(fInviteSDPDescription); - delete[] rtpmapLine; - - char* const cmdFmt = - "INVITE %s SIP/2.0\r\n" - "From: %s ;tag=%u\r\n" - "Via: SIP/2.0/UDP %s:%u\r\n" - "To: %s\r\n" - "Contact: sip:%s@%s:%u\r\n" - "Call-ID: %u@%s\r\n" - "CSeq: %d INVITE\r\n" - "Content-Type: application/sdp\r\n" - "%s" /* Proxy-Authorization: line (if any) */ - "%s" /* User-Agent: line */ - "Content-length: %d\r\n\r\n" - "%s"; - unsigned inviteCmdSize = strlen(cmdFmt) - + fURLSize - + 2*fUserNameSize + fOurAddressStrSize + 20 /* max int len */ - + fOurAddressStrSize + 5 /* max port len */ - + fURLSize - + fUserNameSize + fOurAddressStrSize + 5 - + 20 + fOurAddressStrSize - + 20 - + strlen(authenticatorStr) - + fUserAgentHeaderStrSize - + 20 - + inviteSDPSize; - delete[] fInviteCmd; fInviteCmd = new char[inviteCmdSize]; - sprintf(fInviteCmd, cmdFmt, - fURL, - fUserName, fUserName, fOurAddressStr, fFromTag, - fOurAddressStr, fOurPortNum, - fURL, - fUserName, fOurAddressStr, fOurPortNum, - fCallId, fOurAddressStr, - ++fCSeq, - authenticatorStr, - fUserAgentHeaderStr, - inviteSDPSize, - fInviteSDPDescription); - fInviteCmdSize = strlen(fInviteCmd); - delete[] authenticatorStr; - - // Before sending the "INVITE", arrange to handle any response packets, - // and set up timers: - fInviteClientState = Calling; - fEventLoopStopFlag = 0; - TaskScheduler& sched = envir().taskScheduler(); // abbrev. - sched.turnOnBackgroundReadHandling(fOurSocket->socketNum(), - &inviteResponseHandler, this); - fTimerALen = 1*fT1; // initially - fTimerACount = 0; // initially - fTimerA = sched.scheduleDelayedTask(fTimerALen, timerAHandler, this); - fTimerB = sched.scheduleDelayedTask(64*fT1, timerBHandler, this); - fTimerD = NULL; // for now - - if (!sendINVITE()) break; - - // Enter the event loop, to handle response packets, and timeouts: - envir().taskScheduler().doEventLoop(&fEventLoopStopFlag); - - // We're finished with this "INVITE". - // Turn off response handling and timers: - sched.turnOffBackgroundReadHandling(fOurSocket->socketNum()); - sched.unscheduleDelayedTask(fTimerA); - sched.unscheduleDelayedTask(fTimerB); - sched.unscheduleDelayedTask(fTimerD); - - // NOTE: We return the SDP description that we used in the "INVITE", - // not the one that we got from the server. - // ##### Later: match the codecs in the response (offer, answer) ##### - if (fInviteSDPDescription != NULL) { - return strDup(fInviteSDPDescription); - } - } while (0); - - fInviteStatusCode = 2; - return NULL; -} - -void SIPClient::inviteResponseHandler(void* clientData, int /*mask*/) { - SIPClient* client = (SIPClient*)clientData; - unsigned responseCode = client->getResponseCode(); - client->doInviteStateMachine(responseCode); -} - -// Special 'response codes' that represent timers expiring: -unsigned const timerAFires = 0xAAAAAAAA; -unsigned const timerBFires = 0xBBBBBBBB; -unsigned const timerDFires = 0xDDDDDDDD; - -void SIPClient::timerAHandler(void* clientData) { - SIPClient* client = (SIPClient*)clientData; - if (client->fVerbosityLevel >= 1) { - client->envir() << "RETRANSMISSION " << ++client->fTimerACount - << ", after " << client->fTimerALen/1000000.0 - << " additional seconds\n"; - } - client->doInviteStateMachine(timerAFires); -} - -void SIPClient::timerBHandler(void* clientData) { - SIPClient* client = (SIPClient*)clientData; - if (client->fVerbosityLevel >= 1) { - client->envir() << "RETRANSMISSION TIMEOUT, after " - << 64*client->fT1/1000000.0 << " seconds\n"; - fflush(stderr); - } - client->doInviteStateMachine(timerBFires); -} - -void SIPClient::timerDHandler(void* clientData) { - SIPClient* client = (SIPClient*)clientData; - if (client->fVerbosityLevel >= 1) { - client->envir() << "TIMER D EXPIRED\n"; - } - client->doInviteStateMachine(timerDFires); -} - -void SIPClient::doInviteStateMachine(unsigned responseCode) { - // Implement the state transition diagram (RFC 3261, Figure 5) - TaskScheduler& sched = envir().taskScheduler(); // abbrev. - switch (fInviteClientState) { - case Calling: { - if (responseCode == timerAFires) { - // Restart timer A (with double the timeout interval): - fTimerALen *= 2; - fTimerA - = sched.scheduleDelayedTask(fTimerALen, timerAHandler, this); - - fInviteClientState = Calling; - if (!sendINVITE()) doInviteStateTerminated(0); - } else { - // Turn off timers A & B before moving to a new state: - sched.unscheduleDelayedTask(fTimerA); - sched.unscheduleDelayedTask(fTimerB); - - if (responseCode == timerBFires) { - envir().setResultMsg("No response from server"); - doInviteStateTerminated(0); - } else if (responseCode >= 100 && responseCode <= 199) { - fInviteClientState = Proceeding; - } else if (responseCode >= 200 && responseCode <= 299) { - doInviteStateTerminated(responseCode); - } else if (responseCode >= 400 && responseCode <= 499) { - doInviteStateTerminated(responseCode); - // this isn't what the spec says, but it seems right... - } else if (responseCode >= 300 && responseCode <= 699) { - fInviteClientState = Completed; - fTimerD - = sched.scheduleDelayedTask(32000000, timerDHandler, this); - if (!sendACK()) doInviteStateTerminated(0); - } - } - break; - } - - case Proceeding: { - if (responseCode >= 100 && responseCode <= 199) { - fInviteClientState = Proceeding; - } else if (responseCode >= 200 && responseCode <= 299) { - doInviteStateTerminated(responseCode); - } else if (responseCode >= 400 && responseCode <= 499) { - doInviteStateTerminated(responseCode); - // this isn't what the spec says, but it seems right... - } else if (responseCode >= 300 && responseCode <= 699) { - fInviteClientState = Completed; - fTimerD = sched.scheduleDelayedTask(32000000, timerDHandler, this); - if (!sendACK()) doInviteStateTerminated(0); - } - break; - } - - case Completed: { - if (responseCode == timerDFires) { - envir().setResultMsg("Transaction terminated"); - doInviteStateTerminated(0); - } else if (responseCode >= 300 && responseCode <= 699) { - fInviteClientState = Completed; - if (!sendACK()) doInviteStateTerminated(0); - } - break; - } - - case Terminated: { - doInviteStateTerminated(responseCode); - break; - } - } -} - -void SIPClient::doInviteStateTerminated(unsigned responseCode) { - fInviteClientState = Terminated; // FWIW... - if (responseCode < 200 || responseCode > 299) { - // We failed, so return NULL; - delete[] fInviteSDPDescription; fInviteSDPDescription = NULL; - } - - // Unblock the event loop: - fEventLoopStopFlag = ~0; -} - -Boolean SIPClient::sendINVITE() { - if (!sendRequest(fInviteCmd, fInviteCmdSize)) { - envir().setResultErrMsg("INVITE send() failed: "); - return False; - } - return True; -} - -unsigned SIPClient::getResponseCode() { - unsigned responseCode = 0; - do { - // Get the response from the server: - unsigned const readBufSize = 10000; - char readBuffer[readBufSize+1]; char* readBuf = readBuffer; - - char* firstLine = NULL; - char* nextLineStart = NULL; - unsigned bytesRead = getResponse(readBuf, readBufSize); - if (bytesRead < 0) break; - if (fVerbosityLevel >= 1) { - envir() << "Received INVITE response: " << readBuf << "\n"; - } - - // Inspect the first line to get the response code: - firstLine = readBuf; - nextLineStart = getLine(firstLine); - if (!parseResponseCode(firstLine, responseCode)) break; - - if (responseCode != 200) { - if (responseCode >= 400 && responseCode <= 499 - && fWorkingAuthenticator != NULL) { - // We have an authentication failure, so fill in - // "*fWorkingAuthenticator" using the contents of a following - // "Proxy-Authenticate:" line. (Once we compute a 'response' for - // "fWorkingAuthenticator", it can be used in a subsequent request - // - that will hopefully succeed.) - char* lineStart; - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - if (lineStart[0] == '\0') break; // this is a blank line - - char* realm = strDupSize(lineStart); - char* nonce = strDupSize(lineStart); - // ##### Check for the format of "Proxy-Authenticate:" lines from - // ##### known server types. - // ##### This is a crock! We should make the parsing more general - Boolean foundAuthenticateHeader = False; - if ( - // Asterisk ##### - sscanf(lineStart, "Proxy-Authenticate: Digest realm=\"%[^\"]\", nonce=\"%[^\"]\"", - realm, nonce) == 2 || - // Cisco ATA ##### - sscanf(lineStart, "Proxy-Authenticate: Digest algorithm=MD5,domain=\"%*[^\"]\",nonce=\"%[^\"]\", realm=\"%[^\"]\"", - nonce, realm) == 2) { - fWorkingAuthenticator->setRealmAndNonce(realm, nonce); - foundAuthenticateHeader = True; - } - delete[] realm; delete[] nonce; - if (foundAuthenticateHeader) break; - } - } - envir().setResultMsg("cannot handle INVITE response: ", firstLine); - break; - } - - // Skip every subsequent header line, until we see a blank line. - // While doing so, check for "To:" and "Content-Length:" lines. - // The remaining data is assumed to be the SDP descriptor that we want. - // We should really do some more checking on the headers here - e.g., to - // check for "Content-type: application/sdp", "CSeq", etc. ##### - int contentLength = -1; - char* lineStart; - while (1) { - lineStart = nextLineStart; - if (lineStart == NULL) break; - - nextLineStart = getLine(lineStart); - if (lineStart[0] == '\0') break; // this is a blank line - - char* toTagStr = strDupSize(lineStart); - if (sscanf(lineStart, "To:%*[^;]; tag=%s", toTagStr) == 1) { - delete[] (char*)fToTagStr; fToTagStr = strDup(toTagStr); - fToTagStrSize = strlen(fToTagStr); - } - delete[] toTagStr; - - if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1 - || sscanf(lineStart, "Content-length: %d", &contentLength) == 1) { - if (contentLength < 0) { - envir().setResultMsg("Bad \"Content-length:\" header: \"", - lineStart, "\""); - break; - } - } - } - - // We're now at the end of the response header lines - if (lineStart == NULL) { - envir().setResultMsg("no content following header lines: ", readBuf); - break; - } - - // Use the remaining data as the SDP descr, but first, check - // the "Content-length:" header (if any) that we saw. We may need to - // read more data, or we may have extraneous data in the buffer. - char* bodyStart = nextLineStart; - if (contentLength >= 0) { - // We saw a "Content-length:" header - unsigned numBodyBytes = &readBuf[bytesRead] - bodyStart; - if (contentLength > (int)numBodyBytes) { - // We need to read more data. First, make sure we have enough - // space for it: - unsigned numExtraBytesNeeded = contentLength - numBodyBytes; -#ifdef USING_TCP - // THIS CODE WORKS ONLY FOR TCP: ##### - unsigned remainingBufferSize - = readBufSize - (bytesRead + (readBuf - readBuffer)); - if (numExtraBytesNeeded > remainingBufferSize) { - char tmpBuf[200]; - sprintf(tmpBuf, "Read buffer size (%d) is too small for \"Content-length:\" %d (need a buffer size of >= %d bytes\n", - readBufSize, contentLength, - readBufSize + numExtraBytesNeeded - remainingBufferSize); - envir().setResultMsg(tmpBuf); - break; - } - - // Keep reading more data until we have enough: - if (fVerbosityLevel >= 1) { - envir() << "Need to read " << numExtraBytesNeeded - << " extra bytes\n"; - } - while (numExtraBytesNeeded > 0) { - char* ptr = &readBuf[bytesRead]; - unsigned bytesRead2; - struct sockaddr_in fromAddr; - Boolean readSuccess - = fOurSocket->handleRead((unsigned char*)ptr, - numExtraBytesNeeded, - bytesRead2, fromAddr); - if (!readSuccess) break; - ptr[bytesRead2] = '\0'; - if (fVerbosityLevel >= 1) { - envir() << "Read " << bytesRead2 - << " extra bytes: " << ptr << "\n"; - } - - bytesRead += bytesRead2; - numExtraBytesNeeded -= bytesRead2; - } -#endif - if (numExtraBytesNeeded > 0) break; // one of the reads failed - } - - bodyStart[contentLength] = '\0'; // trims any extra data - } - } while (0); - - return responseCode; -} - -char* SIPClient::inviteWithPassword(char const* url, char const* username, - char const* password) { - delete[] (char*)fUserName; fUserName = strDup(username); - fUserNameSize = strlen(fUserName); - - Authenticator authenticator; - authenticator.setUsernameAndPassword(username, password); - char* inviteResult = invite(url, &authenticator); - if (inviteResult != NULL) { - // We are already authorized - return inviteResult; - } - - // The "realm" and "nonce" fields should have been filled in: - if (authenticator.realm() == NULL || authenticator.nonce() == NULL) { - // We haven't been given enough information to try again, so fail: - return NULL; - } - - // Try again (but with the same CallId): - inviteResult = invite1(&authenticator); - if (inviteResult != NULL) { - // The authenticator worked, so use it in future requests: - fValidAuthenticator = authenticator; - } - - return inviteResult; -} - -Boolean SIPClient::sendACK() { - char* cmd = NULL; - do { - char* const cmdFmt = - "ACK %s SIP/2.0\r\n" - "From: %s ;tag=%u\r\n" - "Via: SIP/2.0/UDP %s:%u\r\n" - "To: %s;tag=%s\r\n" - "Call-ID: %u@%s\r\n" - "CSeq: %d ACK\r\n" - "Content-length: 0\r\n\r\n"; - unsigned cmdSize = strlen(cmdFmt) - + fURLSize - + 2*fUserNameSize + fOurAddressStrSize + 20 /* max int len */ - + fOurAddressStrSize + 5 /* max port len */ - + fURLSize + fToTagStrSize - + 20 + fOurAddressStrSize - + 20; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - fURL, - fUserName, fUserName, fOurAddressStr, fFromTag, - fOurAddressStr, fOurPortNum, - fURL, fToTagStr, - fCallId, fOurAddressStr, - fCSeq /* note: it's the same as before; not incremented */); - - if (!sendRequest(cmd, strlen(cmd))) { - envir().setResultErrMsg("ACK send() failed: "); - break; - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean SIPClient::sendBYE() { - // NOTE: This should really be retransmitted, for reliability ##### - char* cmd = NULL; - do { - char* const cmdFmt = - "BYE %s SIP/2.0\r\n" - "From: %s ;tag=%u\r\n" - "Via: SIP/2.0/UDP %s:%u\r\n" - "To: %s;tag=%s\r\n" - "Call-ID: %u@%s\r\n" - "CSeq: %d ACK\r\n" - "Content-length: 0\r\n\r\n"; - unsigned cmdSize = strlen(cmdFmt) - + fURLSize - + 2*fUserNameSize + fOurAddressStrSize + 20 /* max int len */ - + fOurAddressStrSize + 5 /* max port len */ - + fURLSize + fToTagStrSize - + 20 + fOurAddressStrSize - + 20; - cmd = new char[cmdSize]; - sprintf(cmd, cmdFmt, - fURL, - fUserName, fUserName, fOurAddressStr, fFromTag, - fOurAddressStr, fOurPortNum, - fURL, fToTagStr, - fCallId, fOurAddressStr, - ++fCSeq); - - if (!sendRequest(cmd, strlen(cmd))) { - envir().setResultErrMsg("BYE send() failed: "); - break; - } - - delete[] cmd; - return True; - } while (0); - - delete[] cmd; - return False; -} - -Boolean SIPClient::processURL(char const* url) { - do { - // If we don't already have a server address/port, then - // get these by parsing the URL: - if (fServerAddress.s_addr == 0) { - NetAddress destAddress; - if (!parseSIPURL(envir(), url, destAddress, fServerPortNum)) break; - fServerAddress.s_addr = *(unsigned*)(destAddress.data()); - - if (fOurSocket != NULL) { - fOurSocket->changeDestinationParameters(fServerAddress, - fServerPortNum, 255); - } - } - - return True; - } while (0); - - fInviteStatusCode = 1; - return False; -} - -Boolean SIPClient::parseSIPURL(UsageEnvironment& env, char const* url, - NetAddress& address, - portNumBits& portNum) { - do { - // Parse the URL as "sip:@
:/" - // (with ":" and "/" optional) - // Also, skip over any "[:]@" preceding
- char const* prefix = "sip:"; - unsigned const prefixLength = 4; - if (_strncasecmp(url, prefix, prefixLength) != 0) { - env.setResultMsg("URL is not of the form \"", prefix, "\""); - break; - } - - unsigned const parseBufferSize = 100; - char parseBuffer[parseBufferSize]; - unsigned addressStartIndex = prefixLength; - while (url[addressStartIndex] != '\0' - && url[addressStartIndex++] != '@') {} - char const* from = &url[addressStartIndex]; - - // Skip over any "[:]@" - char const* from1 = from; - while (*from1 != '\0' && *from1 != '/') { - if (*from1 == '@') { - from = ++from1; - break; - } - ++from1; - } - - char* to = &parseBuffer[0]; - unsigned i; - for (i = 0; i < parseBufferSize; ++i) { - if (*from == '\0' || *from == ':' || *from == '/') { - // We've completed parsing the address - *to = '\0'; - break; - } - *to++ = *from++; - } - if (i == parseBufferSize) { - env.setResultMsg("URL is too long"); - break; - } - - NetAddressList addresses(parseBuffer); - if (addresses.numAddresses() == 0) { - env.setResultMsg("Failed to find network address for \"", - parseBuffer, "\""); - break; - } - address = *(addresses.firstAddress()); - - portNum = 5060; // default value - char nextChar = *from; - if (nextChar == ':') { - int portNumInt; - if (sscanf(++from, "%d", &portNumInt) != 1) { - env.setResultMsg("No port number follows ':'"); - break; - } - if (portNumInt < 1 || portNumInt > 65535) { - env.setResultMsg("Bad port number"); - break; - } - portNum = (portNumBits)portNumInt; - } - - return True; - } while (0); - - return False; -} - -Boolean SIPClient::parseSIPURLUsernamePassword(char const* url, - char*& username, - char*& password) { - username = password = NULL; // by default - do { - // Parse the URL as "sip:[:]@" - char const* prefix = "sip:"; - unsigned const prefixLength = 4; - if (_strncasecmp(url, prefix, prefixLength) != 0) break; - - // Look for the ':' and '@': - unsigned usernameIndex = prefixLength; - unsigned colonIndex = 0, atIndex = 0; - for (unsigned i = usernameIndex; url[i] != '\0' && url[i] != '/'; ++i) { - if (url[i] == ':' && colonIndex == 0) { - colonIndex = i; - } else if (url[i] == '@') { - atIndex = i; - break; // we're done - } - } - if (atIndex == 0) break; // no '@' found - - char* urlCopy = strDup(url); - urlCopy[atIndex] = '\0'; - if (colonIndex > 0) { - urlCopy[colonIndex] = '\0'; - password = strDup(&urlCopy[colonIndex+1]); - } else { - password = strDup(""); - } - username = strDup(&urlCopy[usernameIndex]); - delete[] urlCopy; - - return True; - } while (0); - - return False; -} - -char* -SIPClient::createAuthenticatorString(Authenticator const* authenticator, - char const* cmd, char const* url) { - if (authenticator != NULL && authenticator->realm() != NULL - && authenticator->nonce() != NULL && authenticator->username() != NULL - && authenticator->password() != NULL) { - // We've been provided a filled-in authenticator, so use it: - char* const authFmt = "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", response=\"%s\", uri=\"%s\"\r\n"; - char const* response = authenticator->computeDigestResponse(cmd, url); - unsigned authBufSize = strlen(authFmt) - + strlen(authenticator->username()) + strlen(authenticator->realm()) - + strlen(authenticator->nonce()) + strlen(url) + strlen(response); - char* authenticatorStr = new char[authBufSize]; - sprintf(authenticatorStr, authFmt, - authenticator->username(), authenticator->realm(), - authenticator->nonce(), response, url); - authenticator->reclaimDigestResponse(response); - - return authenticatorStr; - } - - return strDup(""); -} - -Boolean SIPClient::sendRequest(char const* requestString, - unsigned requestLength) { - if (fVerbosityLevel >= 1) { - envir() << "Sending request: " << requestString << "\n"; - } - // NOTE: We should really check that "requestLength" is not ##### - // too large for UDP (see RFC 3261, section 18.1.1) ##### - return fOurSocket->output(envir(), 255, (unsigned char*)requestString, - requestLength); -} - -unsigned SIPClient::getResponse(char*& responseBuffer, - unsigned responseBufferSize) { - if (responseBufferSize == 0) return 0; // just in case... - responseBuffer[0] = '\0'; // ditto - - // Keep reading data from the socket until we see "\r\n\r\n" (except - // at the start), or until we fill up our buffer. - // Don't read any more than this. - char* p = responseBuffer; - Boolean haveSeenNonCRLF = False; - int bytesRead = 0; - while (bytesRead < (int)responseBufferSize) { - unsigned bytesReadNow; - struct sockaddr_in fromAddr; - unsigned char* toPosn = (unsigned char*)(responseBuffer+bytesRead); - Boolean readSuccess - = fOurSocket->handleRead(toPosn, responseBufferSize-bytesRead, - bytesReadNow, fromAddr); - if (!readSuccess || bytesReadNow == 0) { - envir().setResultMsg("SIP response was truncated"); - break; - } - bytesRead += bytesReadNow; - - // Check whether we have "\r\n\r\n": - char* lastToCheck = responseBuffer+bytesRead-4; - if (lastToCheck < responseBuffer) continue; - for (; p <= lastToCheck; ++p) { - if (haveSeenNonCRLF) { - if (*p == '\r' && *(p+1) == '\n' && - *(p+2) == '\r' && *(p+3) == '\n') { - responseBuffer[bytesRead] = '\0'; - - // Before returning, trim any \r or \n from the start: - while (*responseBuffer == '\r' || *responseBuffer == '\n') { - ++responseBuffer; - --bytesRead; - } - return bytesRead; - } - } else { - if (*p != '\r' && *p != '\n') { - haveSeenNonCRLF = True; - } - } - } - } - - return 0; -} - -Boolean SIPClient::parseResponseCode(char const* line, - unsigned& responseCode) { - if (sscanf(line, "%*s%u", &responseCode) != 1) { - envir().setResultMsg("no response code in line: \"", line, "\""); - return False; - } - - return True; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/ServerMediaSession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/ServerMediaSession.cpp deleted file mode 100644 index 76842216204..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/ServerMediaSession.cpp +++ /dev/null @@ -1,390 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A data structure that represents a session that consists of -// potentially multiple (audio and/or video) sub-sessions -// (This data structure is used for media *streamers* - i.e., servers. -// For media receivers, use "MediaSession" instead.) -// Implementation - -#include "ServerMediaSession.hh" -#include -#include - -////////// ServerMediaSession ////////// - -ServerMediaSession* ServerMediaSession -::createNew(UsageEnvironment& env, - char const* streamName, char const* info, - char const* description, Boolean isSSM, char const* miscSDPLines) { - return new ServerMediaSession(env, streamName, info, description, - isSSM, miscSDPLines); -} - -Boolean ServerMediaSession -::lookupByName(UsageEnvironment& env, char const* mediumName, - ServerMediaSession*& resultSession) { - resultSession = NULL; // unless we succeed - - Medium* medium; - if (!Medium::lookupByName(env, mediumName, medium)) return False; - - if (!medium->isServerMediaSession()) { - env.setResultMsg(mediumName, " is not a 'ServerMediaSession' object"); - return False; - } - - resultSession = (ServerMediaSession*)medium; - return True; -} - -static char const* const libNameStr = "LIVE555 Streaming Media v"; -char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING; - -ServerMediaSession::ServerMediaSession(UsageEnvironment& env, - char const* streamName, - char const* info, - char const* description, - Boolean isSSM, char const* miscSDPLines) - : Medium(env), fIsSSM(isSSM), fSubsessionsHead(NULL), - fSubsessionsTail(NULL), fSubsessionCounter(0), - fReferenceCount(0), fDeleteWhenUnreferenced(False) { - fStreamName = strDup(streamName == NULL ? "" : streamName); - fInfoSDPString = strDup(info == NULL ? libNameStr : info); - fDescriptionSDPString - = strDup(description == NULL ? libNameStr : description); - fMiscSDPLines = strDup(miscSDPLines == NULL ? "" : miscSDPLines); - - gettimeofday(&fCreationTime, NULL); -} - -ServerMediaSession::~ServerMediaSession() { - Medium::close(fSubsessionsHead); - delete[] fStreamName; - delete[] fInfoSDPString; - delete[] fDescriptionSDPString; - delete[] fMiscSDPLines; -} - -Boolean -ServerMediaSession::addSubsession(ServerMediaSubsession* subsession) { - if (subsession->fParentSession != NULL) return False; // it's already used - - if (fSubsessionsTail == NULL) { - fSubsessionsHead = subsession; - } else { - fSubsessionsTail->fNext = subsession; - } - fSubsessionsTail = subsession; - - subsession->fParentSession = this; - subsession->fTrackNumber = ++fSubsessionCounter; - return True; -} - -void ServerMediaSession::testScaleFactor(float& scale) { - // First, try setting all subsessions to the desired scale. - // If the subsessions' actual scales differ from each other, choose the - // value that's closest to 1, and then try re-setting all subsessions to that - // value. If the subsessions' actual scales still differ, re-set them all to 1. - float minSSScale = 1.0; - float maxSSScale = 1.0; - float bestSSScale = 1.0; - float bestDistanceTo1 = 0.0; - ServerMediaSubsession* subsession; - for (subsession = fSubsessionsHead; subsession != NULL; - subsession = subsession->fNext) { - float ssscale = scale; - subsession->testScaleFactor(ssscale); - if (subsession == fSubsessionsHead) { // this is the first subsession - minSSScale = maxSSScale = bestSSScale = ssscale; - bestDistanceTo1 = (float)fabs(ssscale - 1.0f); - } else { - if (ssscale < minSSScale) { - minSSScale = ssscale; - } else if (ssscale > maxSSScale) { - maxSSScale = ssscale; - } - - float distanceTo1 = (float)fabs(ssscale - 1.0f); - if (distanceTo1 < bestDistanceTo1) { - bestSSScale = ssscale; - bestDistanceTo1 = distanceTo1; - } - } - } - if (minSSScale == maxSSScale) { - // All subsessions are at the same scale: minSSScale == bestSSScale == maxSSScale - scale = minSSScale; - return; - } - - // The scales for each subsession differ. Try to set each one to the value - // that's closest to 1: - for (subsession = fSubsessionsHead; subsession != NULL; - subsession = subsession->fNext) { - float ssscale = bestSSScale; - subsession->testScaleFactor(ssscale); - if (ssscale != bestSSScale) break; // no luck - } - if (subsession == NULL) { - // All subsessions are at the same scale: bestSSScale - scale = bestSSScale; - return; - } - - // Still no luck. Set each subsession's scale to 1: - for (subsession = fSubsessionsHead; subsession != NULL; - subsession = subsession->fNext) { - float ssscale = 1; - subsession->testScaleFactor(ssscale); - } - scale = 1; -} - -float ServerMediaSession::duration() const { - float minSubsessionDuration = 0.0; - float maxSubsessionDuration = 0.0; - for (ServerMediaSubsession* subsession = fSubsessionsHead; subsession != NULL; - subsession = subsession->fNext) { - float ssduration = subsession->duration(); - if (subsession == fSubsessionsHead) { // this is the first subsession - minSubsessionDuration = maxSubsessionDuration = ssduration; - } else if (ssduration < minSubsessionDuration) { - minSubsessionDuration = ssduration; - } else if (ssduration > maxSubsessionDuration) { - maxSubsessionDuration = ssduration; - } - } - - if (maxSubsessionDuration != minSubsessionDuration) { - return -maxSubsessionDuration; // because subsession durations differ - } else { - return maxSubsessionDuration; // all subsession durations are the same - } -} - -Boolean ServerMediaSession::isServerMediaSession() const { - return True; -} - -char* ServerMediaSession::generateSDPDescription() { - struct in_addr ourIPAddress; - ourIPAddress.s_addr = ourSourceAddressForMulticast(envir()); - char* const ourIPAddressStr - = strDup(our_inet_ntoa(ourIPAddress)); - unsigned ourIPAddressStrSize = strlen(ourIPAddressStr); - - // For a SSM sessions, we need a "a=source-filter: incl ..." line also: - char* sourceFilterLine; - if (fIsSSM) { - char const* const sourceFilterFmt = - "a=source-filter: incl IN IP4 * %s\r\n" - "a=rtcp-unicast: reflection\r\n"; - unsigned sourceFilterFmtSize = strlen(sourceFilterFmt) - + ourIPAddressStrSize; - - sourceFilterLine = new char[sourceFilterFmtSize]; - sprintf(sourceFilterLine, sourceFilterFmt, - ourIPAddressStr); - } else { - sourceFilterLine = strDup(""); - } - - char* rangeLine = NULL; // for now - char* sdp = NULL; // for now - - do { - // Count the lengths of each subsession's media-level SDP lines. - // (We do this first, because the call to "subsession->sdpLines()" - // causes correct subsession 'duration()'s to be calculated later.) - unsigned sdpLength = 0; - ServerMediaSubsession* subsession; - for (subsession = fSubsessionsHead; subsession != NULL; - subsession = subsession->fNext) { - char const* sdpLines = subsession->sdpLines(); - if (sdpLines == NULL) break; // the media's not available - sdpLength += strlen(sdpLines); - } - if (subsession != NULL) break; // an error occurred - - // Unless subsessions have differing durations, we also have a "a=range:" line: - float dur = duration(); - if (dur == 0.0) { - rangeLine = strDup("a=range:npt=0-\r\n"); - } else if (dur > 0.0) { - char buf[100]; - sprintf(buf, "a=range:npt=0-%.3f\r\n", dur); - rangeLine = strDup(buf); - } else { // subsessions have differing durations, so "a=range:" lines go there - rangeLine = strDup(""); - } - - char const* const sdpPrefixFmt = - "v=0\r\n" - "o=- %ld%06ld %d IN IP4 %s\r\n" - "s=%s\r\n" - "i=%s\r\n" - "t=0 0\r\n" - "a=tool:%s%s\r\n" - "a=type:broadcast\r\n" - "a=control:*\r\n" - "%s" - "%s" - "a=x-qt-text-nam:%s\r\n" - "a=x-qt-text-inf:%s\r\n" - "%s"; - sdpLength += strlen(sdpPrefixFmt) - + 20 + 6 + 20 + ourIPAddressStrSize - + strlen(fDescriptionSDPString) - + strlen(fInfoSDPString) - + strlen(libNameStr) + strlen(libVersionStr) - + strlen(sourceFilterLine) - + strlen(rangeLine) - + strlen(fDescriptionSDPString) - + strlen(fInfoSDPString) - + strlen(fMiscSDPLines); - sdp = new char[sdpLength]; - if (sdp == NULL) break; - - // Generate the SDP prefix (session-level lines): - sprintf(sdp, sdpPrefixFmt, - fCreationTime.tv_sec, fCreationTime.tv_usec, // o= - 1, // o= // (needs to change if params are modified) - ourIPAddressStr, // o=
- fDescriptionSDPString, // s= - fInfoSDPString, // i= - libNameStr, libVersionStr, // a=tool: - sourceFilterLine, // a=source-filter: incl (if a SSM session) - rangeLine, // a=range: line - fDescriptionSDPString, // a=x-qt-text-nam: line - fInfoSDPString, // a=x-qt-text-inf: line - fMiscSDPLines); // miscellaneous session SDP lines (if any) - - // Then, add the (media-level) lines for each subsession: - char* mediaSDP = sdp; - for (subsession = fSubsessionsHead; subsession != NULL; - subsession = subsession->fNext) { - mediaSDP += strlen(mediaSDP); - sprintf(mediaSDP, "%s", subsession->sdpLines()); - } - } while (0); - - delete[] rangeLine; delete[] sourceFilterLine; delete[] ourIPAddressStr; - return sdp; -} - - -////////// ServerMediaSessionIterator ////////// - -ServerMediaSubsessionIterator -::ServerMediaSubsessionIterator(ServerMediaSession& session) - : fOurSession(session) { - reset(); -} - -ServerMediaSubsessionIterator::~ServerMediaSubsessionIterator() { -} - -ServerMediaSubsession* ServerMediaSubsessionIterator::next() { - ServerMediaSubsession* result = fNextPtr; - - if (fNextPtr != NULL) fNextPtr = fNextPtr->fNext; - - return result; -} - -void ServerMediaSubsessionIterator::reset() { - fNextPtr = fOurSession.fSubsessionsHead; -} - - -////////// ServerMediaSubsession ////////// - -ServerMediaSubsession::ServerMediaSubsession(UsageEnvironment& env) - : Medium(env), - fParentSession(NULL), fServerAddressForSDP(0), fPortNumForSDP(0), - fNext(NULL), fTrackNumber(0), fTrackId(NULL) { -} - -ServerMediaSubsession::~ServerMediaSubsession() { - delete[] (char*)fTrackId; - Medium::close(fNext); -} - -char const* ServerMediaSubsession::trackId() { - if (fTrackNumber == 0) return NULL; // not yet in a ServerMediaSession - - if (fTrackId == NULL) { - char buf[100]; - sprintf(buf, "track%d", fTrackNumber); - fTrackId = strDup(buf); - } - return fTrackId; -} - -void ServerMediaSubsession::pauseStream(unsigned /*clientSessionId*/, - void* /*streamToken*/) { - // default implementation: do nothing -} -void ServerMediaSubsession::seekStream(unsigned /*clientSessionId*/, - void* /*streamToken*/, float /*seekNPT*/) { - // default implementation: do nothing -} -void ServerMediaSubsession::setStreamScale(unsigned /*clientSessionId*/, - void* /*streamToken*/, float /*scale*/) { - // default implementation: do nothing -} -void ServerMediaSubsession::deleteStream(unsigned /*clientSessionId*/, - void*& /*streamToken*/) { - // default implementation: do nothing -} - -void ServerMediaSubsession::testScaleFactor(float& scale) { - // default implementation: Support scale = 1 only - scale = 1; -} - -float ServerMediaSubsession::duration() const { - // default implementation: assume an unbounded session: - return 0.0; -} - -void ServerMediaSubsession::setServerAddressAndPortForSDP(netAddressBits addressBits, - portNumBits portBits) { - fServerAddressForSDP = addressBits; - fPortNumForSDP = portBits; -} - -char const* -ServerMediaSubsession::rangeSDPLine() const { - if (fParentSession == NULL) return NULL; - - // If all of our parent's subsessions have the same duration - // (as indicated by "fParentSession->duration() >= 0"), there's no "a=range:" line: - if (fParentSession->duration() >= 0.0) return strDup(""); - - // Use our own duration for a "a=range:" line: - float ourDuration = duration(); - if (ourDuration == 0.0) { - return strDup("a=range:npt=0-\r\n"); - } else { - char buf[100]; - sprintf(buf, "a=range:npt=0-%.3f\r\n", ourDuration); - return strDup(buf); - } -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/SimpleRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/SimpleRTPSink.cpp deleted file mode 100644 index a94c227fd66..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/SimpleRTPSink.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simple RTP sink that packs frames into each outgoing -// packet, without any fragmentation or special headers. -// Implementation - -#include "SimpleRTPSink.hh" - -SimpleRTPSink::SimpleRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* sdpMediaTypeString, - char const* rtpPayloadFormatName, - unsigned numChannels, - Boolean allowMultipleFramesPerPacket, - Boolean doNormalMBitRule) - : MultiFramedRTPSink(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, rtpPayloadFormatName, - numChannels), - fAllowMultipleFramesPerPacket(allowMultipleFramesPerPacket) { - fSDPMediaTypeString - = strDup(sdpMediaTypeString == NULL ? "unknown" : sdpMediaTypeString); - fSetMBitOnLastFrames - = strcmp(fSDPMediaTypeString, "video") == 0 && doNormalMBitRule; -} - -SimpleRTPSink::~SimpleRTPSink() { - delete[] (char*)fSDPMediaTypeString; -} - -SimpleRTPSink* -SimpleRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* sdpMediaTypeString, - char const* rtpPayloadFormatName, - unsigned numChannels, - Boolean allowMultipleFramesPerPacket, - Boolean doNormalMBitRule) { - return new SimpleRTPSink(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency, - sdpMediaTypeString, rtpPayloadFormatName, - numChannels, - allowMultipleFramesPerPacket, - doNormalMBitRule); -} - -void SimpleRTPSink::doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes) { - if (numRemainingBytes == 0) { - // This packet contains the last (or only) fragment of the frame. - // Set the RTP 'M' ('marker') bit, if appropriate: - if (fSetMBitOnLastFrames) setMarkerBit(); - } - - // Important: Also call our base class's doSpecialFrameHandling(), - // to set the packet's timestamp: - MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset, - frameStart, numBytesInFrame, - frameTimestamp, - numRemainingBytes); -} - -Boolean SimpleRTPSink:: -frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/, - unsigned /*numBytesInFrame*/) const { - return fAllowMultipleFramesPerPacket; -} - -char const* SimpleRTPSink::sdpMediaType() const { - return fSDPMediaTypeString; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/SimpleRTPSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/SimpleRTPSource.cpp deleted file mode 100644 index e64be1d2baf..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/SimpleRTPSource.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A RTP source for a simple RTP payload format that -// - doesn't have any special headers following the RTP header -// - doesn't have any special framing apart from the packet data itself -// Implementation - -#include "SimpleRTPSource.hh" -#include - -SimpleRTPSource* -SimpleRTPSource::createNew(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mimeTypeString, - unsigned offset, Boolean doNormalMBitRule) { - return new SimpleRTPSource(env, RTPgs, rtpPayloadFormat, - rtpTimestampFrequency, - mimeTypeString, offset, doNormalMBitRule); -} - -SimpleRTPSource -::SimpleRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mimeTypeString, - unsigned offset, Boolean doNormalMBitRule) - : MultiFramedRTPSource(env, RTPgs, - rtpPayloadFormat, rtpTimestampFrequency), - fMIMEtypeString(strDup(mimeTypeString)), fOffset(offset) { - fUseMBitForFrameEnd - = strncmp(mimeTypeString, "video/", 6) == 0 && doNormalMBitRule; -} - -SimpleRTPSource::~SimpleRTPSource() { - delete[] (char*)fMIMEtypeString; -} - -Boolean SimpleRTPSource -::processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize) { - fCurrentPacketCompletesFrame - = !fUseMBitForFrameEnd || packet->rtpMarkerBit(); - - resultSpecialHeaderSize = fOffset; - return True; -} - -char const* SimpleRTPSource::MIMEtype() const { - if (fMIMEtypeString == NULL) return MultiFramedRTPSource::MIMEtype(); - - return fMIMEtypeString; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/StreamParser.cpp b/mythtv/libs/libmythlivemedia/liveMedia/StreamParser.cpp deleted file mode 100644 index 82fc97588e4..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/StreamParser.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Abstract class for parsing a byte stream -// Implementation - -#include "StreamParser.hh" - -#include -#include - -#define BANK_SIZE 150000 - -StreamParser::StreamParser(FramedSource* inputSource, - FramedSource::onCloseFunc* onInputCloseFunc, - void* onInputCloseClientData, - clientContinueFunc* clientContinueFunc, - void* clientContinueClientData) - : fInputSource(inputSource), fOnInputCloseFunc(onInputCloseFunc), - fOnInputCloseClientData(onInputCloseClientData), - fClientContinueFunc(clientContinueFunc), - fClientContinueClientData(clientContinueClientData), - fSavedParserIndex(0), fSavedRemainingUnparsedBits(0), - fCurParserIndex(0), fRemainingUnparsedBits(0), - fTotNumValidBytes(0) { - fBank[0] = new unsigned char[BANK_SIZE]; - fBank[1] = new unsigned char[BANK_SIZE]; - fCurBankNum = 0; - fCurBank = fBank[fCurBankNum]; -} - -StreamParser::~StreamParser() { - delete[] fBank[0]; delete[] fBank[1]; -} - -#define NO_MORE_BUFFERED_INPUT 1 - -void StreamParser::ensureValidBytes1(unsigned numBytesNeeded) { - // We need to read some more bytes from the input source. - // First, clarify how much data to ask for: - unsigned maxInputFrameSize = fInputSource->maxFrameSize(); - if (maxInputFrameSize > numBytesNeeded) numBytesNeeded = maxInputFrameSize; - - // First, check whether these new bytes would overflow the current - // bank. If so, start using a new bank now. - if (fCurParserIndex + numBytesNeeded > BANK_SIZE) { - // Swap banks, but save any still-needed bytes from the old bank: - unsigned numBytesToSave = fTotNumValidBytes - fSavedParserIndex; - unsigned char const* from = &curBank()[fSavedParserIndex]; - - fCurBankNum = (fCurBankNum + 1)%2; - fCurBank = fBank[fCurBankNum]; - memmove(curBank(), from, numBytesToSave); - fCurParserIndex = fCurParserIndex - fSavedParserIndex; - fSavedParserIndex = 0; - fTotNumValidBytes = numBytesToSave; - } - - // ASSERT: fCurParserIndex + numBytesNeeded > fTotNumValidBytes - // && fCurParserIndex + numBytesNeeded <= BANK_SIZE - if (fCurParserIndex + numBytesNeeded > BANK_SIZE) { - // If this happens, it means that we have too much saved parser state. - // To fix this, increase BANK_SIZE as appropriate. - fInputSource->envir() << "StreamParser internal error (" - << fCurParserIndex << "+ " - << numBytesNeeded << " > " - << BANK_SIZE << ")\n"; - exit(1); - } - - // Try to read as many new bytes as will fit in the current bank: - unsigned maxNumBytesToRead = BANK_SIZE - fTotNumValidBytes; - fInputSource->getNextFrame(&curBank()[fTotNumValidBytes], - maxNumBytesToRead, - afterGettingBytes, this, - fOnInputCloseFunc, fOnInputCloseClientData); - - throw NO_MORE_BUFFERED_INPUT; -} - -void StreamParser::afterGettingBytes(void* clientData, - unsigned numBytesRead, - unsigned /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned /*durationInMicroseconds*/){ - StreamParser* buffer = (StreamParser*)clientData; - - // Sanity check: Make sure we didn't get too many bytes for our bank: - if (buffer->fTotNumValidBytes + numBytesRead > BANK_SIZE) { - buffer->fInputSource->envir() - << "StreamParser::afterGettingBytes() warning: read " - << numBytesRead << " bytes; expected no more than " - << BANK_SIZE - buffer->fTotNumValidBytes << "\n"; - } - - unsigned char* ptr = &buffer->curBank()[buffer->fTotNumValidBytes]; - buffer->fTotNumValidBytes += numBytesRead; - - // Continue our original calling source where it left off: - buffer->restoreSavedParserState(); - // Sigh... this is a crock; things would have been a lot simpler - // here if we were using threads, with synchronous I/O... - buffer->fClientContinueFunc(buffer->fClientContinueClientData, - ptr, numBytesRead, presentationTime); -} - -void StreamParser::saveParserState() { - fSavedParserIndex = fCurParserIndex; - fSavedRemainingUnparsedBits = fRemainingUnparsedBits; -} - -void StreamParser::restoreSavedParserState() { - fCurParserIndex = fSavedParserIndex; - fRemainingUnparsedBits = fSavedRemainingUnparsedBits; -} - -void StreamParser::skipBits(unsigned numBits) { - if (numBits <= fRemainingUnparsedBits) { - fRemainingUnparsedBits -= numBits; - } else { - numBits -= fRemainingUnparsedBits; - - unsigned numBytesToExamine = (numBits+7)/8; // round up - ensureValidBytes(numBytesToExamine); - fCurParserIndex += numBytesToExamine; - - fRemainingUnparsedBits = 8*numBytesToExamine - numBits; - } -} - -unsigned StreamParser::getBits(unsigned numBits) { - if (numBits <= fRemainingUnparsedBits) { - unsigned char lastByte = *lastParsed(); - lastByte >>= (fRemainingUnparsedBits - numBits); - fRemainingUnparsedBits -= numBits; - - return (unsigned)lastByte &~ ((~0)< 0) { - lastByte = *lastParsed(); - } else { - lastByte = 0; - } - - unsigned remainingBits = numBits - fRemainingUnparsedBits; // > 0 - - // For simplicity, read the next 4 bytes, even though we might not - // need all of them here: - unsigned result = test4Bytes(); - - result >>= (32 - remainingBits); - result |= (lastByte << remainingBits); - if (numBits < 32) result &=~ ((~0)<.) - -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Abstract class for parsing a byte stream -// C++ header - -#ifndef _STREAM_PARSER_HH -#define _STREAM_PARSER_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -class StreamParser { -public: - virtual void flushInput(); - -protected: // we're a virtual base class - typedef void (clientContinueFunc)(void* clientData, - unsigned char* ptr, unsigned size, - struct timeval presentationTime); - StreamParser(FramedSource* inputSource, - FramedSource::onCloseFunc* onInputCloseFunc, - void* onInputCloseClientData, - clientContinueFunc* clientContinueFunc, - void* clientContinueClientData); - virtual ~StreamParser(); - - void saveParserState(); - virtual void restoreSavedParserState(); - - u_int32_t get4Bytes() { // byte-aligned; returned in big-endian order - u_int32_t result = test4Bytes(); - fCurParserIndex += 4; - fRemainingUnparsedBits = 0; - - return result; - } - u_int32_t test4Bytes() { // as above, but doesn't advance ptr - ensureValidBytes(4); - - unsigned char const* ptr = nextToParse(); - return (ptr[0]<<24)|(ptr[1]<<16)|(ptr[2]<<8)|ptr[3]; - } - - u_int16_t get2Bytes() { - ensureValidBytes(2); - - unsigned char const* ptr = nextToParse(); - u_int16_t result = (ptr[0]<<8)|ptr[1]; - - fCurParserIndex += 2; - fRemainingUnparsedBits = 0; - - return result; - } - - u_int8_t get1Byte() { // byte-aligned - ensureValidBytes(1); - fRemainingUnparsedBits = 0; - return curBank()[fCurParserIndex++]; - } - - void getBytes(u_int8_t* to, unsigned numBytes) { - ensureValidBytes(numBytes); - memmove(to, nextToParse(), numBytes); - fCurParserIndex += numBytes; - fRemainingUnparsedBits = 0; - } - void skipBytes(unsigned numBytes) { - ensureValidBytes(numBytes); - fCurParserIndex += numBytes; - } - - void skipBits(unsigned numBits); - unsigned getBits(unsigned numBits); - // numBits <= 32; returns data into low-order bits of result - - unsigned curOffset() const { return fCurParserIndex; } - - unsigned& totNumValidBytes() { return fTotNumValidBytes; } - -private: - unsigned char* curBank() { return fCurBank; } - unsigned char* nextToParse() { return &curBank()[fCurParserIndex]; } - unsigned char* lastParsed() { return &curBank()[fCurParserIndex-1]; } - - // makes sure that at least "numBytes" valid bytes remain: - void ensureValidBytes(unsigned numBytesNeeded) { - // common case: inlined: - if (fCurParserIndex + numBytesNeeded <= fTotNumValidBytes) return; - - ensureValidBytes1(numBytesNeeded); - } - void ensureValidBytes1(unsigned numBytesNeeded); - - static void afterGettingBytes(void* clientData, unsigned numBytesRead, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - FramedSource* fInputSource; // should be a byte-stream source?? - FramedSource::onCloseFunc* fOnInputCloseFunc; - void* fOnInputCloseClientData; - clientContinueFunc* fClientContinueFunc; - void* fClientContinueClientData; - - // Use a pair of 'banks', and swap between them as they fill up: - unsigned char* fBank[2]; - unsigned char fCurBankNum; - unsigned char* fCurBank; - - // The most recent 'saved' parse position: - unsigned fSavedParserIndex; // <= fCurParserIndex - unsigned char fSavedRemainingUnparsedBits; - - // The current position of the parser within the current bank: - unsigned fCurParserIndex; // <= fTotNumValidBytes - unsigned char fRemainingUnparsedBits; // in previous byte: [0,7] - - // The total number of valid bytes stored in the current bank: - unsigned fTotNumValidBytes; // <= BANK_SIZE -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/VideoRTPSink.cpp b/mythtv/libs/libmythlivemedia/liveMedia/VideoRTPSink.cpp deleted file mode 100644 index 696392c5244..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/VideoRTPSink.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A generic RTP sink for video codecs (abstract base class) -// Implementation - -#include "VideoRTPSink.hh" - -VideoRTPSink::VideoRTPSink(UsageEnvironment& env, - Groupsock* rtpgs, unsigned char rtpPayloadType, - unsigned rtpTimestampFrequency, - char const* rtpPayloadFormatName) - : MultiFramedRTPSink(env, rtpgs, rtpPayloadType, rtpTimestampFrequency, - rtpPayloadFormatName) { -} - -VideoRTPSink::~VideoRTPSink() { -} - -char const* VideoRTPSink::sdpMediaType() const { - return "video"; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/WAVAudioFileServerMediaSubsession.cpp b/mythtv/libs/libmythlivemedia/liveMedia/WAVAudioFileServerMediaSubsession.cpp deleted file mode 100644 index d4218da3935..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/WAVAudioFileServerMediaSubsession.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from an WAV audio file. -// Implementation - -#include "WAVAudioFileServerMediaSubsession.hh" -#include "WAVAudioFileSource.hh" -#include "uLawAudioFilter.hh" -#include "SimpleRTPSink.hh" - -WAVAudioFileServerMediaSubsession* WAVAudioFileServerMediaSubsession -::createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource, - Boolean convertToULaw) { - return new WAVAudioFileServerMediaSubsession(env, fileName, - reuseFirstSource, convertToULaw); -} - -WAVAudioFileServerMediaSubsession -::WAVAudioFileServerMediaSubsession(UsageEnvironment& env, char const* fileName, - Boolean reuseFirstSource, Boolean convertToULaw) - : FileServerMediaSubsession(env, fileName, reuseFirstSource), - fConvertToULaw(convertToULaw) { -} - -WAVAudioFileServerMediaSubsession -::~WAVAudioFileServerMediaSubsession() { -} - -void WAVAudioFileServerMediaSubsession -::seekStreamSource(FramedSource* inputSource, float seekNPT) { - WAVAudioFileSource* wavSource; - if (fBitsPerSample == 16) { - // "inputSource" is a filter; its input source is the original WAV file source: - wavSource = (WAVAudioFileSource*)(((FramedFilter*)inputSource)->inputSource()); - } else { - // "inputSource" is the original WAV file source: - wavSource = (WAVAudioFileSource*)inputSource; - } - - unsigned seekSampleNumber = (unsigned)(seekNPT*fSamplingFrequency); - unsigned seekByteNumber = (seekSampleNumber*fNumChannels*fBitsPerSample)/8; - - wavSource->seekToPCMByte(seekByteNumber); -} - -void WAVAudioFileServerMediaSubsession -::setStreamSourceScale(FramedSource* inputSource, float scale) { - int iScale = (int)scale; - WAVAudioFileSource* wavSource; - if (fBitsPerSample == 16) { - // "inputSource" is a filter; its input source is the original WAV file source: - wavSource = (WAVAudioFileSource*)(((FramedFilter*)inputSource)->inputSource()); - } else { - // "inputSource" is the original WAV file source: - wavSource = (WAVAudioFileSource*)inputSource; - } - - wavSource->setScaleFactor(iScale); -} - -FramedSource* WAVAudioFileServerMediaSubsession -::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) { - FramedSource* resultSource = NULL; - do { - WAVAudioFileSource* wavSource - = WAVAudioFileSource::createNew(envir(), fFileName); - if (wavSource == NULL) break; - - // Get attributes of the audio source: - fBitsPerSample = wavSource->bitsPerSample(); - if (fBitsPerSample != 8 && fBitsPerSample != 16) { - envir() << "The input file contains " << fBitsPerSample - << " bit-per-sample audio, which we don't handle\n"; - break; - } - fSamplingFrequency = wavSource->samplingFrequency(); - fNumChannels = wavSource->numChannels(); - unsigned bitsPerSecond - = fSamplingFrequency*fBitsPerSample*fNumChannels; - - fFileDuration = (float)((8.0*wavSource->numPCMBytes()) - /(fSamplingFrequency*fNumChannels*fBitsPerSample)); - - // Add in any filter necessary to transform the data prior to streaming: - if (fBitsPerSample == 16) { - // Note that samples in the WAV audio file are in little-endian order. - if (fConvertToULaw) { - // Add a filter that converts from raw 16-bit PCM audio - // to 8-bit u-law audio: - resultSource - = uLawFromPCMAudioSource::createNew(envir(), wavSource, 1/*little-endian*/); - bitsPerSecond /= 2; - } else { - // Add a filter that converts from little-endian to network (big-endian) order: - resultSource = EndianSwap16::createNew(envir(), wavSource); - } - } else { // fBitsPerSample == 8 - // Don't do any transformation; send the 8-bit PCM data 'as is': - resultSource = wavSource; - } - - estBitrate = (bitsPerSecond+500)/1000; // kbps - return resultSource; - } while (0); - - // An error occurred: - Medium::close(resultSource); - return NULL; -} - -RTPSink* WAVAudioFileServerMediaSubsession -::createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* /*inputSource*/) { - do { - char* mimeType; - unsigned char payloadFormatCode; - if (fBitsPerSample == 16) { - if (fConvertToULaw) { - mimeType = "PCMU"; - if (fSamplingFrequency == 8000 && fNumChannels == 1) { - payloadFormatCode = 0; // a static RTP payload type - } else { - payloadFormatCode = rtpPayloadTypeIfDynamic; - } - } else { - mimeType = "L16"; - if (fSamplingFrequency == 44100 && fNumChannels == 2) { - payloadFormatCode = 10; // a static RTP payload type - } else if (fSamplingFrequency == 44100 && fNumChannels == 1) { - payloadFormatCode = 11; // a static RTP payload type - } else { - payloadFormatCode = rtpPayloadTypeIfDynamic; - } - } - } else { // fBitsPerSample == 8 - mimeType = "L8"; - payloadFormatCode = rtpPayloadTypeIfDynamic; - } - - return SimpleRTPSink::createNew(envir(), rtpGroupsock, - payloadFormatCode, fSamplingFrequency, - "audio", mimeType, fNumChannels); - } while (0); - - // An error occurred: - return NULL; -} - -void WAVAudioFileServerMediaSubsession::testScaleFactor(float& scale) { - if (fFileDuration <= 0.0) { - // The file is non-seekable, so is probably a live input source. - // We don't support scale factors other than 1 - scale = 1; - } else { - // We support any integral scale, other than 0 - int iScale = scale < 0.0 ? (int)(scale - 0.5) : (int)(scale + 0.5); // round - if (iScale == 0) iScale = 1; - scale = (float)iScale; - } -} - -float WAVAudioFileServerMediaSubsession::duration() const { - return fFileDuration; -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/WAVAudioFileSource.cpp b/mythtv/libs/libmythlivemedia/liveMedia/WAVAudioFileSource.cpp deleted file mode 100644 index 638c2ffdf88..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/WAVAudioFileSource.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A WAV audio file source -// Implementation - -#include "WAVAudioFileSource.hh" -#include "InputFile.hh" -#include "GroupsockHelper.hh" - -////////// WAVAudioFileSource ////////// - -WAVAudioFileSource* -WAVAudioFileSource::createNew(UsageEnvironment& env, char const* fileName) { - do { - FILE* fid = OpenInputFile(env, fileName); - if (fid == NULL) break; - - WAVAudioFileSource* newSource = new WAVAudioFileSource(env, fid); - if (newSource != NULL && newSource->bitsPerSample() == 0) { - // The WAV file header was apparently invalid. - Medium::close(newSource); - break; - } - - newSource->fFileSize = (unsigned)GetFileSize(fileName, fid); - - return newSource; - } while (0); - - return NULL; -} - -unsigned WAVAudioFileSource::numPCMBytes() const { - if (fFileSize < fWAVHeaderSize) return 0; - return fFileSize - fWAVHeaderSize; -} - -void WAVAudioFileSource::setScaleFactor(int scale) { - fScaleFactor = scale; - - if (fScaleFactor < 0 && ftell(fFid) > 0) { - // Because we're reading backwards, seek back one sample, to ensure that - // (i) we start reading the last sample before the start point, and - // (ii) we don't hit end-of-file on the first read. - int const bytesPerSample = (fNumChannels*fBitsPerSample)/8; - fseek(fFid, -bytesPerSample, SEEK_CUR); - } -} - -void WAVAudioFileSource::seekToPCMByte(unsigned byteNumber) { - byteNumber += fWAVHeaderSize; - if (byteNumber > fFileSize) byteNumber = fFileSize; - - fseek(fFid, byteNumber, SEEK_SET); -} - -#define nextc fgetc(fid) -#define ucEOF ((unsigned char)EOF) - -static Boolean get4Bytes(FILE* fid, unsigned& result) { // little-endian - unsigned char c0, c1, c2, c3; - if ((c0 = nextc) == ucEOF || (c1 = nextc) == ucEOF || - (c2 = nextc) == ucEOF || (c3 = nextc) == ucEOF) return False; - result = (c3<<24)|(c2<<16)|(c1<<8)|c0; - return True; -} - -static Boolean get2Bytes(FILE* fid, unsigned short& result) {//little-endian - unsigned char c0, c1; - if ((c0 = nextc) == ucEOF || (c1 = nextc) == ucEOF) return False; - result = (c1<<8)|c0; - return True; -} - -static Boolean skipBytes(FILE* fid, int num) { - while (num-- > 0) { - if (nextc == ucEOF) return False; - } - return True; -} - -WAVAudioFileSource::WAVAudioFileSource(UsageEnvironment& env, FILE* fid) - : AudioInputDevice(env, 0, 0, 0, 0)/* set the real parameters later */, - fFid(fid), fLastPlayTime(0), fWAVHeaderSize(0), fFileSize(0), fScaleFactor(1) { - // Check the WAV file header for validity. - // Note: The following web pages contain info about the WAV format: - // http://www.technology.niagarac.on.ca/courses/comp630/WavFileFormat.html - // http://ccrma-www.stanford.edu/CCRMA/Courses/422/projects/WaveFormat/ - // http://www.ringthis.com/dev/wave_format.htm - // http://www.lightlink.com/tjweber/StripWav/Canon.html - // http://www.borg.com/~jglatt/tech/wave.htm - // http://www.wotsit.org/download.asp?f=wavecomp - - Boolean success = False; // until we learn otherwise - do { - // RIFF Chunk: - if (nextc != 'R' || nextc != 'I' || nextc != 'F' || nextc != 'F') break; - if (!skipBytes(fid, 4)) break; - if (nextc != 'W' || nextc != 'A' || nextc != 'V' || nextc != 'E') break; - - // FORMAT Chunk: - if (nextc != 'f' || nextc != 'm' || nextc != 't' || nextc != ' ') break; - unsigned formatLength; - if (!get4Bytes(fid, formatLength)) break; - unsigned short audioFormat; - if (!get2Bytes(fid, audioFormat)) break; - if (audioFormat != 1) { // not PCM - we can't handle this - env.setResultMsg("Audio format is not PCM"); - break; - } - unsigned short numChannels; - if (!get2Bytes(fid, numChannels)) break; - fNumChannels = (unsigned char)numChannels; - if (fNumChannels < 1 || fNumChannels > 2) { // invalid # channels - char errMsg[100]; - sprintf(errMsg, "Bad # channels: %d", fNumChannels); - env.setResultMsg(errMsg); - break; - } - if (!get4Bytes(fid, fSamplingFrequency)) break; - if (fSamplingFrequency == 0) { - env.setResultMsg("Bad sampling frequency: 0"); - break; - } - if (!skipBytes(fid, 6)) break; - unsigned short bitsPerSample; - if (!get2Bytes(fid, bitsPerSample)) break; - fBitsPerSample = (unsigned char)bitsPerSample; - if (fBitsPerSample == 0) { - env.setResultMsg("Bad bits-per-sample: 0"); - break; - } - if (!skipBytes(fid, formatLength - 16)) break; - - // FACT chunk (optional): - unsigned char c = nextc; - if (c == 'f') { - if (nextc != 'a' || nextc != 'c' || nextc != 't') break; - unsigned factLength; - if (!get4Bytes(fid, factLength)) break; - if (!skipBytes(fid, factLength)) break; - c = nextc; - } - - // DATA Chunk: - if (c != 'd' || nextc != 'a' || nextc != 't' || nextc != 'a') break; - if (!skipBytes(fid, 4)) break; - - // The header is good; the remaining data are the sample bytes. - fWAVHeaderSize = ftell(fid); - success = True; - } while (0); - - if (!success) { - env.setResultMsg("Bad WAV file format"); - // Set "fBitsPerSample" to zero, to indicate failure: - fBitsPerSample = 0; - return; - } - - fPlayTimePerSample = 1e6/(double)fSamplingFrequency; - - // Although PCM is a sample-based format, we group samples into - // 'frames' for efficient delivery to clients. Set up our preferred - // frame size to be close to 20 ms, if possible, but always no greater - // than 1400 bytes (to ensure that it will fit in a single RTP packet) - unsigned maxSamplesPerFrame = (1400*8)/(fNumChannels*fBitsPerSample); - unsigned desiredSamplesPerFrame = (unsigned)(0.02*fSamplingFrequency); - unsigned samplesPerFrame = desiredSamplesPerFrame < maxSamplesPerFrame - ? desiredSamplesPerFrame : maxSamplesPerFrame; - fPreferredFrameSize = (samplesPerFrame*fNumChannels*fBitsPerSample)/8; -} - -WAVAudioFileSource::~WAVAudioFileSource() { - CloseInputFile(fFid); -} - -void WAVAudioFileSource::doGetNextFrame() { - if (feof(fFid) || ferror(fFid)) { - handleClosure(this); - return; - } - - // Try to read as many bytes as will fit in the buffer provided - // (or "fPreferredFrameSize" if less) - if (fPreferredFrameSize < fMaxSize) { - fMaxSize = fPreferredFrameSize; - } - unsigned const bytesPerSample = (fNumChannels*fBitsPerSample)/8; - unsigned bytesToRead = fMaxSize - fMaxSize%bytesPerSample; - if (fScaleFactor == 1) { - // Common case - read samples in bulk: - fFrameSize = fread(fTo, 1, bytesToRead, fFid); - } else { - // We read every 'fScaleFactor'th sample: - fFrameSize = 0; - while (bytesToRead > 0) { - size_t bytesRead = fread(fTo, 1, bytesPerSample, fFid); - if (bytesRead <= 0) break; - fTo += bytesRead; - fFrameSize += bytesRead; - bytesToRead -= bytesRead; - - // Seek to the appropriate place for the next sample: - fseek(fFid, (fScaleFactor-1)*bytesPerSample, SEEK_CUR); - } - } - - // Set the 'presentation time' and 'duration' of this frame: - if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) { - // This is the first frame, so use the current time: - gettimeofday(&fPresentationTime, NULL); - } else { - // Increment by the play time of the previous data: - unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime; - fPresentationTime.tv_sec += uSeconds/1000000; - fPresentationTime.tv_usec = uSeconds%1000000; - } - - // Remember the play time of this data: - fDurationInMicroseconds = fLastPlayTime - = (unsigned)((fPlayTimePerSample*fFrameSize)/bytesPerSample); - - // Switch to another task, and inform the reader that he has data: -#if defined(__WIN32__) || defined(_WIN32) - // HACK: One of our applications that uses this source uses an - // implementation of scheduleDelayedTask() that performs very badly - // (chewing up lots of CPU time, apparently polling) on Windows. - // Until this is fixed, we just call our "afterGetting()" function - // directly. This avoids infinite recursion, as long as our sink - // is discontinuous, which is the case for the RTP sink that - // this application uses. ##### - afterGetting(this); -#else - nextTask() = envir().taskScheduler().scheduleDelayedTask(0, - (TaskFunc*)FramedSource::afterGetting, this); -#endif -} - -Boolean WAVAudioFileSource::setInputPort(int /*portIndex*/) { - return True; -} - -double WAVAudioFileSource::getAverageLevel() const { - return 0.0;//##### fix this later -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioRTPSink.hh deleted file mode 100644 index 4ebf36de41c..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioRTPSink.hh +++ /dev/null @@ -1,55 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for AC3 audio -// C++ header - -#ifndef _AC3_AUDIO_RTP_SINK_HH -#define _AC3_AUDIO_RTP_SINK_HH - -#ifndef _AUDIO_RTP_SINK_HH -#include "AudioRTPSink.hh" -#endif - -class AC3AudioRTPSink: public AudioRTPSink { -public: - static AC3AudioRTPSink* createNew(UsageEnvironment& env, - Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency); - -protected: - AC3AudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency); - // called only by createNew() - - virtual ~AC3AudioRTPSink(); - -private: // redefined virtual functions: - virtual - Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual unsigned specialHeaderSize() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioRTPSource.hh deleted file mode 100644 index c4fd751eb3f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioRTPSource.hh +++ /dev/null @@ -1,51 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// AC3 Audio RTP Sources -// C++ header - -#ifndef _AC3_AUDIO_RTP_SOURCE_HH -#define _AC3_AUDIO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class AC3AudioRTPSource: public MultiFramedRTPSource { -public: - static AC3AudioRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - -protected: - virtual ~AC3AudioRTPSource(); - -private: - AC3AudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioStreamFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioStreamFramer.hh deleted file mode 100644 index 3cc7d380b21..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AC3AudioStreamFramer.hh +++ /dev/null @@ -1,67 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an AC3 audio elementary stream into frames -// C++ header - -#ifndef _AC3_AUDIO_STREAM_FRAMER_HH -#define _AC3_AUDIO_STREAM_FRAMER_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - -class AC3AudioStreamFramer: public FramedFilter { -public: - static AC3AudioStreamFramer* - createNew(UsageEnvironment& env, FramedSource* inputSource, - unsigned char streamCode = 0x80); - - unsigned samplingRate(); - - void flushInput(); // called if there is a discontinuity (seeking) in the input - -private: - AC3AudioStreamFramer(UsageEnvironment& env, FramedSource* inputSource, - unsigned char streamCode); - // called only by createNew() - virtual ~AC3AudioStreamFramer(); - - static void handleNewData(void* clientData, - unsigned char* ptr, unsigned size, - struct timeval presentationTime); - void handleNewData(unsigned char* ptr, unsigned size); - - void parseNextFrame(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - struct timeval currentFramePlayTime() const; - -private: - struct timeval fNextFramePresentationTime; - -private: // parsing state - class AC3AudioStreamParser* fParser; - unsigned char fOurStreamCode; - friend class AC3AudioStreamParser; // hack -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/ADTSAudioFileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/ADTSAudioFileServerMediaSubsession.hh deleted file mode 100644 index 1de059e961d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/ADTSAudioFileServerMediaSubsession.hh +++ /dev/null @@ -1,48 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from an AAC audio file in ADTS format -// C++ header - -#ifndef _ADTS_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH -#define _ADTS_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#include "FileServerMediaSubsession.hh" -#endif - -class ADTSAudioFileServerMediaSubsession: public FileServerMediaSubsession{ -public: - static ADTSAudioFileServerMediaSubsession* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); - -private: - ADTSAudioFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource); - // called only by createNew(); - virtual ~ADTSAudioFileServerMediaSubsession(); - -private: // redefined virtual functions - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/ADTSAudioFileSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/ADTSAudioFileSource.hh deleted file mode 100644 index df3298a1262..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/ADTSAudioFileSource.hh +++ /dev/null @@ -1,56 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A source object for AAC audio files in ADTS format -// C++ header - -#ifndef _ADTS_AUDIO_FILE_SOURCE_HH -#define _ADTS_AUDIO_FILE_SOURCE_HH - -#ifndef _FRAMED_FILE_SOURCE_HH -#include "FramedFileSource.hh" -#endif - -class ADTSAudioFileSource: public FramedFileSource { -public: - static ADTSAudioFileSource* createNew(UsageEnvironment& env, - char const* fileName); - - unsigned samplingFrequency() const { return fSamplingFrequency; } - unsigned numChannels() const { return fNumChannels; } - char const* configStr() const { return fConfigStr; } - // returns the 'AudioSpecificConfig' for this stream (in ASCII form) - -private: - ADTSAudioFileSource(UsageEnvironment& env, FILE* fid, u_int8_t profile, - u_int8_t samplingFrequencyIndex, u_int8_t channelConfiguration); - // called only by createNew() - - virtual ~ADTSAudioFileSource(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - unsigned fSamplingFrequency; - unsigned fNumChannels; - unsigned fuSecsPerFrame; - char fConfigStr[5]; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileServerMediaSubsession.hh deleted file mode 100644 index 48b6796ff57..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileServerMediaSubsession.hh +++ /dev/null @@ -1,48 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from an AMR audio file. -// C++ header - -#ifndef _AMR_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH -#define _AMR_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#include "FileServerMediaSubsession.hh" -#endif - -class AMRAudioFileServerMediaSubsession: public FileServerMediaSubsession{ -public: - static AMRAudioFileServerMediaSubsession* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); - -private: - AMRAudioFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource); - // called only by createNew(); - virtual ~AMRAudioFileServerMediaSubsession(); - -private: // redefined virtual functions - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileSink.hh deleted file mode 100644 index e84f0c0e0b3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileSink.hh +++ /dev/null @@ -1,50 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// AMR Audio File Sinks -// C++ header - -#ifndef _AMR_AUDIO_FILE_SINK_HH -#define _AMR_AUDIO_FILE_SINK_HH - -#ifndef _FILE_SINK_HH -#include "FileSink.hh" -#endif - -class AMRAudioFileSink: public FileSink { -public: - static AMRAudioFileSink* createNew(UsageEnvironment& env, char const* fileName, - unsigned bufferSize = 10000, - Boolean oneFilePerFrame = False); - // (See "FileSink.hh" for a description of these parameters.) - -private: - AMRAudioFileSink(UsageEnvironment& env, FILE* fid, unsigned bufferSize, - char const* perFrameFileNamePrefix); - // called only by createNew() - virtual ~AMRAudioFileSink(); - -private: // redefined virtual functions: - virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); - virtual void afterGettingFrame1(unsigned frameSize, - struct timeval presentationTime); - -private: - Boolean fHaveWrittenHeader; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileSource.hh deleted file mode 100644 index 362b5bc50f8..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioFileSource.hh +++ /dev/null @@ -1,48 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A source object for AMR audio files (as defined in RFC 3267, section 5) -// C++ header - -#ifndef _AMR_AUDIO_FILE_SOURCE_HH -#define _AMR_AUDIO_FILE_SOURCE_HH - -#ifndef _AMR_AUDIO_SOURCE_HH -#include "AMRAudioSource.hh" -#endif - -class AMRAudioFileSource: public AMRAudioSource { -public: - static AMRAudioFileSource* createNew(UsageEnvironment& env, - char const* fileName); - -private: - AMRAudioFileSource(UsageEnvironment& env, FILE* fid, - Boolean isWideband, unsigned numChannels); - // called only by createNew() - - virtual ~AMRAudioFileSource(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - FILE* fFid; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioRTPSink.hh deleted file mode 100644 index c0ba6f6fb66..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioRTPSink.hh +++ /dev/null @@ -1,63 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for AMR audio (RFC 3267) -// C++ header - -#ifndef _AMR_AUDIO_RTP_SINK_HH -#define _AMR_AUDIO_RTP_SINK_HH - -#ifndef _AUDIO_RTP_SINK_HH -#include "AudioRTPSink.hh" -#endif - -class AMRAudioRTPSink: public AudioRTPSink { -public: - static AMRAudioRTPSink* createNew(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - Boolean sourceIsWideband = False, - unsigned numChannelsInSource = 1); - -protected: - AMRAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - Boolean sourceIsWideband, unsigned numChannelsInSource); - // called only by createNew() - - virtual ~AMRAudioRTPSink(); - -private: // redefined virtual functions: - virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual Boolean - frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - - virtual unsigned specialHeaderSize() const; - virtual char const* auxSDPLine(); - -private: - Boolean fSourceIsWideband; - char* fAuxSDPLine; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioRTPSource.hh deleted file mode 100644 index a498e05292e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioRTPSource.hh +++ /dev/null @@ -1,53 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// AMR Audio RTP Sources (RFC 3267) -// C++ header - -#ifndef _AMR_AUDIO_RTP_SOURCE_HH -#define _AMR_AUDIO_RTP_SOURCE_HH - -#ifndef _RTP_SOURCE_HH -#include "RTPSource.hh" -#endif -#ifndef _AMR_AUDIO_SOURCE_HH -#include "AMRAudioSource.hh" -#endif - -class AMRAudioRTPSource { -public: - static AMRAudioSource* createNew(UsageEnvironment& env, - Groupsock* RTPgs, - RTPSource*& resultRTPSource, - unsigned char rtpPayloadFormat, - Boolean isWideband = False, - unsigned numChannels = 1, - Boolean isOctetAligned = True, - unsigned interleaving = 0, - // relevant only if "isOctetAligned" - // The maximum # of frame-blocks in a group - // 0 means: no interleaving - Boolean robustSortingOrder = False, - // relevant only if "isOctetAligned" - Boolean CRCsArePresent = False - // relevant only if "isOctetAligned" - ); - // This returns a source to read from, but "resultRTPSource" will - // point to RTP-related state. -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioSource.hh deleted file mode 100644 index 04e19923022..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AMRAudioSource.hh +++ /dev/null @@ -1,51 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A source object for AMR audio sources -// C++ header - -#ifndef _AMR_AUDIO_SOURCE_HH -#define _AMR_AUDIO_SOURCE_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -class AMRAudioSource: public FramedSource { -public: - Boolean isWideband() const { return fIsWideband; } - unsigned numChannels() const { return fNumChannels; } - - u_int8_t lastFrameHeader() const { return fLastFrameHeader; } - // The frame header for the most recently read frame (RFC 3267, sec. 5.3) - -protected: - AMRAudioSource(UsageEnvironment& env, Boolean isWideband, unsigned numChannels); - // virtual base class - virtual ~AMRAudioSource(); - -private: - // redefined virtual functions: - virtual Boolean isAMRAudioSource() const; - -protected: - Boolean fIsWideband; - unsigned fNumChannels; - u_int8_t fLastFrameHeader; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AVIFileSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AVIFileSink.hh deleted file mode 100644 index 5b0c9b11df5..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AVIFileSink.hh +++ /dev/null @@ -1,112 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A sink that generates an AVI file from a composite media session -// C++ header - -#ifndef _AVI_FILE_SINK_HH -#define _AVI_FILE_SINK_HH - -#ifndef _MEDIA_SESSION_HH -#include "MediaSession.hh" -#endif - -class AVIFileSink: public Medium { -public: - static AVIFileSink* createNew(UsageEnvironment& env, - MediaSession& inputSession, - char const* outputFileName, - unsigned bufferSize = 20000, - unsigned short movieWidth = 240, - unsigned short movieHeight = 180, - unsigned movieFPS = 15, - Boolean packetLossCompensate = False); - - typedef void (afterPlayingFunc)(void* clientData); - Boolean startPlaying(afterPlayingFunc* afterFunc, - void* afterClientData); - - unsigned numActiveSubsessions() const { return fNumSubsessions; } - -private: - AVIFileSink(UsageEnvironment& env, MediaSession& inputSession, - FILE* outFid, unsigned bufferSize, - unsigned short movieWidth, unsigned short movieHeight, - unsigned movieFPS, Boolean packetLossCompensate); - // called only by createNew() - virtual ~AVIFileSink(); - - Boolean continuePlaying(); - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - static void onSourceClosure(void* clientData); - void onSourceClosure1(); - static void onRTCPBye(void* clientData); - void completeOutputFile(); - -private: - friend class AVISubsessionIOState; - MediaSession& fInputSession; - FILE* fOutFid; - unsigned fBufferSize; - Boolean fPacketLossCompensate; - Boolean fAreCurrentlyBeingPlayed; - afterPlayingFunc* fAfterFunc; - void* fAfterClientData; - unsigned fNumSubsessions; - unsigned fNumBytesWritten; - struct timeval fStartTime; - Boolean fHaveCompletedOutputFile; - -private: - ///// Definitions specific to the AVI file format: - - unsigned addWord(unsigned word); // outputs "word" in little-endian order - unsigned addHalfWord(unsigned short halfWord); - unsigned addByte(unsigned char byte) { - putc(byte, fOutFid); - return 1; - } - unsigned addZeroWords(unsigned numWords); - unsigned add4ByteString(char const* str); - void setWord(unsigned filePosn, unsigned size); - - // Define member functions for outputting various types of file header: -#define _header(name) unsigned addFileHeader_##name() - _header(AVI); - _header(hdrl); - _header(avih); - _header(strl); - _header(strh); - _header(strf); - _header(JUNK); -// _header(JUNK); - _header(movi); -private: - unsigned short fMovieWidth, fMovieHeight; - unsigned fMovieFPS; - unsigned fRIFFSizePosition, fRIFFSizeValue; - unsigned fAVIHMaxBytesPerSecondPosition; - unsigned fAVIHFrameCountPosition; - unsigned fMoviSizePosition, fMoviSizeValue; - class AVISubsessionIOState* fCurrentIOState; - unsigned fJunkNumber; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AudioInputDevice.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AudioInputDevice.hh deleted file mode 100644 index 9b8f93d9d93..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AudioInputDevice.hh +++ /dev/null @@ -1,71 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Generic audio input device (such as a microphone, or an input sound card) -// C++ header - -#ifndef _AUDIO_INPUT_DEVICE_HH -#define _AUDIO_INPUT_DEVICE_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -class AudioPortNames { -public: - AudioPortNames(); - virtual ~AudioPortNames(); - - unsigned numPorts; - char** portName; -}; - -class AudioInputDevice: public FramedSource { -public: - unsigned char bitsPerSample() const { return fBitsPerSample; } - unsigned char numChannels() const { return fNumChannels; } - unsigned samplingFrequency() const { return fSamplingFrequency; } - - virtual Boolean setInputPort(int portIndex) = 0; - virtual double getAverageLevel() const = 0; - - static AudioInputDevice* - createNew(UsageEnvironment& env, int inputPortNumber, - unsigned char bitsPerSample, unsigned char numChannels, - unsigned samplingFrequency, unsigned granularityInMS = 20); - static AudioPortNames* getPortNames(); - - static char** allowedDeviceNames; - // If this is set to non-NULL, then it's a NULL-terminated array of strings - // of device names that we are allowed to access. - -protected: - AudioInputDevice(UsageEnvironment& env, - unsigned char bitsPerSample, - unsigned char numChannels, - unsigned samplingFrequency, - unsigned granularityInMS); - // we're an abstract base class - - virtual ~AudioInputDevice(); - -protected: - unsigned char fBitsPerSample, fNumChannels; - unsigned fSamplingFrequency; - unsigned fGranularityInMS; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/AudioRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/AudioRTPSink.hh deleted file mode 100644 index 4609587c126..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/AudioRTPSink.hh +++ /dev/null @@ -1,42 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A generic RTP sink for audio codecs (abstract base class) -// C++ header - -#ifndef _AUDIO_RTP_SINK_HH -#define _AUDIO_RTP_SINK_HH - -#ifndef _MULTI_FRAMED_RTP_SINK_HH -#include "MultiFramedRTPSink.hh" -#endif - -class AudioRTPSink: public MultiFramedRTPSink { -protected: - AudioRTPSink(UsageEnvironment& env, - Groupsock* rtpgs, unsigned char rtpPayloadType, - unsigned rtpTimestampFrequency, - char const* rtpPayloadFormatName, - unsigned numChannels = 1); - // (we're an abstract base class) - virtual ~AudioRTPSink(); - -private: // redefined virtual functions: - virtual char const* sdpMediaType() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/Base64.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/Base64.hh deleted file mode 100644 index 5630031e53c..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/Base64.hh +++ /dev/null @@ -1,37 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Base64 encoding and decoding -// C++ header - -#ifndef _BASE64_HH -#define _BASE64_HH - -#ifndef _BOOLEAN_HH -#include "Boolean.hh" -#endif - -unsigned char* base64Decode(char* in, unsigned& resultSize, - Boolean trimTrailingZeros = True); - // returns a newly allocated array - of size "resultSize" - that - // the caller is responsible for delete[]ing. - -char* base64Encode(char const* orig); - // returns a 0-terminated string that - // the caller is responsible for delete[]ing. - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/BasicUDPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/BasicUDPSink.hh deleted file mode 100644 index 3ef69c98bcd..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/BasicUDPSink.hh +++ /dev/null @@ -1,62 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simple UDP sink (i.e., without RTP or other headers added); one frame per packet -// C++ header - -#ifndef _SIMPLE_UDP_SINK_HH -#define _SIMPLE_UDP_SINK_HH - -#ifndef _MEDIA_SINK_HH -#include "MediaSink.hh" -#endif -#ifndef _GROUPSOCK_HH -#include -#endif - -class BasicUDPSink: public MediaSink { -public: - static BasicUDPSink* createNew(UsageEnvironment& env, Groupsock* gs, - unsigned maxPayloadSize = 1450); -protected: - BasicUDPSink(UsageEnvironment& env, Groupsock* gs, unsigned maxPayloadSize); - // called only by createNew() - virtual ~BasicUDPSink(); - -private: // redefined virtual functions: - virtual Boolean continuePlaying(); - -private: - void continuePlaying1(); - - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - unsigned durationInMicroseconds); - - static void sendNext(void* firstArg); - -private: - Groupsock* fGS; - unsigned fMaxPayloadSize; - unsigned char* fOutputBuffer; - struct timeval fNextSendTime; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/BasicUDPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/BasicUDPSource.hh deleted file mode 100644 index ab80653e844..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/BasicUDPSource.hh +++ /dev/null @@ -1,54 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simple UDP source, where every UDP payload is a complete frame -// C++ header - -#ifndef _BASIC_UDP_SOURCE_HH -#define _BASIC_UDP_SOURCE_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif -#ifndef _GROUPSOCK_HH -#include "Groupsock.hh" -#endif - -class BasicUDPSource: public FramedSource { -public: - static BasicUDPSource* createNew(UsageEnvironment& env, Groupsock* inputGS); - - virtual ~BasicUDPSource(); - - Groupsock* gs() const { return fInputGS; } - -private: - BasicUDPSource(UsageEnvironment& env, Groupsock* inputGS); - // called only by createNew() - - static void incomingPacketHandler(BasicUDPSource* source, int mask); - void incomingPacketHandler1(); - -private: // redefined virtual functions: - virtual void doGetNextFrame(); - virtual void doStopGettingFrames(); - -private: - Groupsock* fInputGS; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/ByteStreamFileSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/ByteStreamFileSource.hh deleted file mode 100644 index 1425c241f59..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/ByteStreamFileSource.hh +++ /dev/null @@ -1,72 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A file source that is a plain byte stream (rather than frames) -// C++ header - -#ifndef _BYTE_STREAM_FILE_SOURCE_HH -#define _BYTE_STREAM_FILE_SOURCE_HH - -#ifndef _FRAMED_FILE_SOURCE_HH -#include "FramedFileSource.hh" -#endif - -class ByteStreamFileSource: public FramedFileSource { -public: - static ByteStreamFileSource* createNew(UsageEnvironment& env, - char const* fileName, - unsigned preferredFrameSize = 0, - unsigned playTimePerFrame = 0); - // "preferredFrameSize" == 0 means 'no preference' - // "playTimePerFrame" is in microseconds - - static ByteStreamFileSource* createNew(UsageEnvironment& env, - FILE* fid, - Boolean deleteFidOnClose = False, - unsigned preferredFrameSize = 0, - unsigned playTimePerFrame = 0); - // an alternative version of "createNew()" that's used if you already have - // an open file. - - u_int64_t fileSize() const { return fFileSize; } - // 0 means zero-length, unbounded, or unknown - - void seekToByteAbsolute(u_int64_t byteNumber); - void seekToByteRelative(int64_t offset); - -protected: - ByteStreamFileSource(UsageEnvironment& env, - FILE* fid, Boolean deleteFidOnClose, - unsigned preferredFrameSize, - unsigned playTimePerFrame); - // called only by createNew() - - virtual ~ByteStreamFileSource(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - unsigned fPreferredFrameSize; - unsigned fPlayTimePerFrame; - unsigned fLastPlayTime; - u_int64_t fFileSize; - Boolean fDeleteFidOnClose; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/ByteStreamMultiFileSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/ByteStreamMultiFileSource.hh deleted file mode 100644 index 65595569395..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/ByteStreamMultiFileSource.hh +++ /dev/null @@ -1,67 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A source that consists of multiple byte-stream files, read sequentially -// C++ header - -#ifndef _BYTE_STREAM_MULTI_FILE_SOURCE_HH -#define _BYTE_STREAM_MULTI_FILE_SOURCE_HH - -#ifndef _BYTE_STREAM_FILE_SOURCE_HH -#include "ByteStreamFileSource.hh" -#endif - -class ByteStreamMultiFileSource: public FramedSource { -public: - static ByteStreamMultiFileSource* - createNew(UsageEnvironment& env, char const** fileNameArray, - unsigned preferredFrameSize = 0, unsigned playTimePerFrame = 0); - // A 'filename' of NULL indicates the end of the array - - Boolean haveStartedNewFile() const { return fHaveStartedNewFile; } - // True iff the most recently delivered frame was the first from a newly-opened file - -protected: - ByteStreamMultiFileSource(UsageEnvironment& env, char const** fileNameArray, - unsigned preferredFrameSize, unsigned playTimePerFrame); - // called only by createNew() - - virtual ~ByteStreamMultiFileSource(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - static void onSourceClosure(void* clientData); - void onSourceClosure1(); - static void afterGettingFrame(void* clientData, - unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - unsigned fPreferredFrameSize; - unsigned fPlayTimePerFrame; - unsigned fNumSources; - unsigned fCurrentlyReadSourceNumber; - Boolean fHaveStartedNewFile; - char const** fFileNameArray; - ByteStreamFileSource** fSourceArray; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/DarwinInjector.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/DarwinInjector.hh deleted file mode 100644 index 07ab3035a77..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/DarwinInjector.hh +++ /dev/null @@ -1,97 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// An object that redirects one or more RTP/RTCP streams - forming a single -// multimedia session - into a 'Darwin Streaming Server' (for subsequent -// reflection to potentially arbitrarily many remote RTSP clients). -// C++ header - -#ifndef _DARWIN_INJECTOR_HH -#define _DARWIN_INJECTOR_HH - -#ifndef _RTSP_CLIENT_HH -#include -#endif - -#ifndef _RTCP_HH -#include -#endif - -/* -To use a "DarwinInjector": - 1/ Create RTP sinks and RTCP instances for each audio or video subsession. - Note: These can use 0.0.0.0 for the address, and 0 for the port number, - of each 'groupsock') - 2/ Call "addStream()" for each. - 3/ Call "setDestination()" to specify the remote Darwin Streaming Server. - Note: You must have 'write' permission on the Darwin Streaming Server. - This can be set up using a "qtaccess" file in the server's 'movies' - directory. For example, the following "qtaccess" file allows anyone to - play streams from the server, but allows only valid users to - inject streams *into* the server: - - require valid-user - - require any-user - Use the "remoteUserName" and "remotePassword" parameters to - "setDestination()", as appropriate. - 4/ Call "startPlaying" on each RTP sink (from the corresponding 'source'). -*/ - -class SubstreamDescriptor; // forward - -class DarwinInjector: public Medium { -public: - static DarwinInjector* createNew(UsageEnvironment& env, - char const* applicationName = NULL, - int verbosityLevel = 0); - - static Boolean lookupByName(UsageEnvironment& env, char const* name, - DarwinInjector*& result); - - void addStream(RTPSink* rtpSink, RTCPInstance* rtcpInstance); - - Boolean setDestination(char const* remoteRTSPServerNameOrAddress, - char const* remoteFileName, - char const* sessionName = "", - char const* sessionInfo = "", - portNumBits remoteRTSPServerPortNumber = 554, - char const* remoteUserName = "", - char const* remotePassword = "", - char const* sessionAuthor = "", - char const* sessionCopyright = ""); - -private: // redefined virtual functions - virtual Boolean isDarwinInjector() const; - -private: - DarwinInjector(UsageEnvironment& env, - char const* applicationName, int verbosityLevel); - // called only by createNew() - - virtual ~DarwinInjector(); - -private: - char const* fApplicationName; - int fVerbosityLevel; - RTSPClient* fRTSPClient; - unsigned fSubstreamSDPSizes; - SubstreamDescriptor* fHeadSubstream; - SubstreamDescriptor* fTailSubstream; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/DeviceSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/DeviceSource.hh deleted file mode 100644 index cc6b2d188b5..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/DeviceSource.hh +++ /dev/null @@ -1,53 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A template for a MediaSource encapsulating an audio/video input device -// C++ header - -#ifndef _DEVICE_SOURCE_HH -#define _DEVICE_SOURCE_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -// The following class can be used to define specific encoder parameters -class DeviceParameters { -}; - -class DeviceSource: public FramedSource { -public: - static DeviceSource* createNew(UsageEnvironment& env, - DeviceParameters params); - -protected: - DeviceSource(UsageEnvironment& env, DeviceParameters params); - // called only by createNew(), or by subclass constructors - virtual ~DeviceSource(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - void deliverFrame(); - -private: - DeviceParameters fParams; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/DigestAuthentication.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/DigestAuthentication.hh deleted file mode 100644 index 1da8d7f32db..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/DigestAuthentication.hh +++ /dev/null @@ -1,72 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A class used for digest authentication. -// C++ header - -#ifndef _DIGEST_AUTHENTICATION_HH -#define _DIGEST_AUTHENTICATION_HH - -#ifndef _BOOLEAN_HH -#include -#endif - -// A class used for digest authentication. -// The "realm", and "nonce" fields are supplied by the server -// (in a "401 Unauthorized" response). -// The "username" and "password" fields are supplied by the client. -class Authenticator { -public: - Authenticator(); - Authenticator(const Authenticator& orig); - Authenticator& operator=(const Authenticator& rightSide); - virtual ~Authenticator(); - - void reset(); - void setRealmAndNonce(char const* realm, char const* nonce); - void setRealmAndRandomNonce(char const* realm); - // as above, except that the nonce is created randomly. - // (This is used by servers.) - void setUsernameAndPassword(char const* username, char const* password, - Boolean passwordIsMD5 = False); - // If "passwordIsMD5" is True, then "password" is actually the value computed - // by md5(::) - - char const* realm() const { return fRealm; } - char const* nonce() const { return fNonce; } - char const* username() const { return fUsername; } - char const* password() const { return fPassword; } - - char const* computeDigestResponse(char const* cmd, char const* url) const; - void reclaimDigestResponse(char const* responseStr) const; - -private: - void resetRealmAndNonce(); - void resetUsernameAndPassword(); - void assignRealmAndNonce(char const* realm, char const* nonce); - void assignUsernameAndPassword(char const* username, char const* password, - Boolean passwordIsMD5); - void assign(char const* realm, char const* nonce, - char const* username, char const* password, Boolean passwordIsMD5); - -private: - char* fRealm; char* fNonce; - char* fUsername; char* fPassword; - Boolean fPasswordIsMD5; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/FileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/FileServerMediaSubsession.hh deleted file mode 100644 index 1b1e2c25b0e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/FileServerMediaSubsession.hh +++ /dev/null @@ -1,40 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a file. -// C++ header - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#define _FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH -#include "OnDemandServerMediaSubsession.hh" -#endif - -class FileServerMediaSubsession: public OnDemandServerMediaSubsession { -protected: // we're a virtual base class - FileServerMediaSubsession(UsageEnvironment& env, char const* fileName, - Boolean reuseFirstSource); - virtual ~FileServerMediaSubsession(); - -protected: - char const* fFileName; - u_int64_t fFileSize; // if known -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/FileSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/FileSink.hh deleted file mode 100644 index 07a5c3066aa..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/FileSink.hh +++ /dev/null @@ -1,69 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// File Sinks -// C++ header - -#ifndef _FILE_SINK_HH -#define _FILE_SINK_HH - -#ifndef _MEDIA_SINK_HH -#include "MediaSink.hh" -#endif - -class FileSink: public MediaSink { -public: - static FileSink* createNew(UsageEnvironment& env, char const* fileName, - unsigned bufferSize = 20000, - Boolean oneFilePerFrame = False); - // "bufferSize" should be at least as large as the largest expected - // input frame. - // "oneFilePerFrame" - if True - specifies that each input frame will - // be written to a separate file (using the presentation time as a - // file name suffix). The default behavior ("oneFilePerFrame" == False) - // is to output all incoming data into a single file. - - void addData(unsigned char* data, unsigned dataSize, - struct timeval presentationTime); - // (Available in case a client wants to add extra data to the output file) - -protected: - FileSink(UsageEnvironment& env, FILE* fid, unsigned bufferSize, - char const* perFrameFileNamePrefix); - // called only by createNew() - virtual ~FileSink(); - -protected: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - virtual void afterGettingFrame1(unsigned frameSize, - struct timeval presentationTime); - - FILE* fOutFid; - unsigned char* fBuffer; - unsigned fBufferSize; - char* fPerFrameFileNamePrefix; // used if "oneFilePerFrame" is True - char* fPerFrameFileNameBuffer; // used if "oneFilePerFrame" is True - -private: // redefined virtual functions: - virtual Boolean continuePlaying(); -}; - - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/FramedFileSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/FramedFileSource.hh deleted file mode 100644 index 928c1ab1e3f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/FramedFileSource.hh +++ /dev/null @@ -1,37 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Framed File Sources -// C++ header - -#ifndef _FRAMED_FILE_SOURCE_HH -#define _FRAMED_FILE_SOURCE_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -class FramedFileSource: public FramedSource { -protected: - FramedFileSource(UsageEnvironment& env, FILE* fid); // abstract base class - virtual ~FramedFileSource(); - -protected: - FILE* fFid; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/FramedFilter.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/FramedFilter.hh deleted file mode 100644 index c99e12285aa..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/FramedFilter.hh +++ /dev/null @@ -1,47 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Framed Filters -// C++ header - -#ifndef _FRAMED_FILTER_HH -#define _FRAMED_FILTER_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -class FramedFilter: public FramedSource { -public: - FramedSource* inputSource() const { return fInputSource; } - -protected: - FramedFilter(UsageEnvironment& env, FramedSource* inputSource); - // abstract base class - virtual ~FramedFilter(); - -protected: - // Redefined virtual functions (with default 'null' implementations): - virtual char const* MIMEtype() const; - virtual void getAttributes() const; - virtual void doStopGettingFrames(); - -protected: - FramedSource* fInputSource; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/FramedSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/FramedSource.hh deleted file mode 100644 index 99f188f9ca1..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/FramedSource.hh +++ /dev/null @@ -1,110 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Framed Sources -// C++ header - -#ifndef _FRAMED_SOURCE_HH -#define _FRAMED_SOURCE_HH - -#ifndef _NET_COMMON_H -#include "NetCommon.h" -#endif -#ifndef _MEDIA_SOURCE_HH -#include "MediaSource.hh" -#endif - -class FramedSource: public MediaSource { -public: - static Boolean lookupByName(UsageEnvironment& env, char const* sourceName, - FramedSource*& resultSource); - - typedef void (afterGettingFunc)(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - typedef void (onCloseFunc)(void* clientData); - void getNextFrame(unsigned char* to, unsigned maxSize, - afterGettingFunc* afterGettingFunc, - void* afterGettingClientData, - onCloseFunc* onCloseFunc, - void* onCloseClientData); - // ##### The following is for backwards-compatibility; remove it eventually: -#ifdef BACKWARDS_COMPATIBLE_WITH_OLD_AFTER_GETTING_FUNC - typedef void (bwCompatAfterGettingFunc)(void* clientData, unsigned frameSize, - struct timeval presentationTime); - void getNextFrame(unsigned char* to, unsigned maxSize, - bwCompatAfterGettingFunc* afterGettingFunc, - void* afterGettingClientData, - onCloseFunc* onCloseFunc, - void* onCloseClientData); - bwCompatAfterGettingFunc* fSavedBWCompatAfterGettingFunc; - void* fSavedBWCompatAfterGettingClientData; -#endif - // ##### End of code for backwards-compatibility. - - static void handleClosure(void* clientData); - // This should be called (on ourself) if the source is discovered - // to be closed (i.e., no longer readable) - - void stopGettingFrames(); - - virtual unsigned maxFrameSize() const; - // size of the largest possible frame that we may serve, or 0 - // if no such maximum is known (default) - - virtual void doGetNextFrame() = 0; - // called by getNextFrame() - - Boolean isCurrentlyAwaitingData() const {return fIsCurrentlyAwaitingData;} - - // Tests for specific types of 'framed source': - virtual Boolean isPrioritizedRTPStreamSelector() const; - -protected: - FramedSource(UsageEnvironment& env); // abstract base class - virtual ~FramedSource(); - - static void afterGetting(FramedSource* source); - // doGetNextFrame() should arrange for this to be called after the - // frame has been read (*iff* it is read successfully) - - virtual void doStopGettingFrames(); - -protected: - // The following variables are typically accessed/set by doGetNextFrame() - unsigned char* fTo; // in - unsigned fMaxSize; // in - unsigned fFrameSize; // out - unsigned fNumTruncatedBytes; // out - struct timeval fPresentationTime; // out - unsigned fDurationInMicroseconds; // out - -private: - // redefined virtual functions: - virtual Boolean isFramedSource() const; - -private: - afterGettingFunc* fAfterGettingFunc; - void* fAfterGettingClientData; - onCloseFunc* fOnCloseFunc; - void* fOnCloseClientData; - - Boolean fIsCurrentlyAwaitingData; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/GSMAudioRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/GSMAudioRTPSink.hh deleted file mode 100644 index 576159d77af..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/GSMAudioRTPSink.hh +++ /dev/null @@ -1,44 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for GSM audio -// C++ header - -#ifndef _GSM_AUDIO_RTP_SINK_HH -#define _GSM_AUDIO_RTP_SINK_HH - -#ifndef _AUDIO_RTP_SINK_HH -#include "AudioRTPSink.hh" -#endif - -class GSMAudioRTPSink: public AudioRTPSink { -public: - static GSMAudioRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs); - -protected: - GSMAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs); - // called only by createNew() - - virtual ~GSMAudioRTPSink(); - -private: // redefined virtual functions: - virtual - Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/H261VideoRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/H261VideoRTPSource.hh deleted file mode 100644 index 7b7114aea70..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/H261VideoRTPSource.hh +++ /dev/null @@ -1,56 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// H.261 Video RTP Sources -// C++ header - -#ifndef _H261_VIDEO_RTP_SOURCE_HH -#define _H261_VIDEO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class H261VideoRTPSource: public MultiFramedRTPSource { -public: - static H261VideoRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat = 31, - unsigned rtpTimestampFrequency = 90000); - - u_int32_t lastSpecialHeader() const {return fLastSpecialHeader;} - -protected: - virtual ~H261VideoRTPSource(); - -private: - H261VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; - -private: - u_int32_t fLastSpecialHeader; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoFileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoFileServerMediaSubsession.hh deleted file mode 100644 index 46709e567b3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoFileServerMediaSubsession.hh +++ /dev/null @@ -1,57 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-4 video file. -// C++ header - -#ifndef _H263PLUS_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH -#define _H263PLUS_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#include "FileServerMediaSubsession.hh" -#endif - -class H263plusVideoFileServerMediaSubsession: public FileServerMediaSubsession{ -public: - static H263plusVideoFileServerMediaSubsession* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); - - void setDoneFlag() { fDoneFlag = ~0; } - void checkForAuxSDPLine1(); - -private: - H263plusVideoFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource); - // called only by createNew(); - virtual ~H263plusVideoFileServerMediaSubsession(); - -private: // redefined virtual functions - virtual char const* getAuxSDPLine(RTPSink* rtpSink, - FramedSource* inputSource); - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); - -private: - char fDoneFlag; // used when setting up "fSDPLines" - RTPSink* fDummyRTPSink; // ditto -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoRTPSink.hh deleted file mode 100644 index e1c931ff0c9..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoRTPSink.hh +++ /dev/null @@ -1,54 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for H.263+ video (RFC 2429) -// C++ header - -#ifndef _H263_PLUS_VIDEO_RTP_SINK_HH -#define _H263_PLUS_VIDEO_RTP_SINK_HH - -#ifndef _VIDEO_RTP_SINK_HH -#include "VideoRTPSink.hh" -#endif - -class H263plusVideoRTPSink: public VideoRTPSink { -public: - static H263plusVideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency = 90000); - -protected: - H263plusVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency); - // called only by createNew() - - virtual ~H263plusVideoRTPSink(); - -private: // redefined virtual functions: - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual - Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - virtual unsigned specialHeaderSize() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoRTPSource.hh deleted file mode 100644 index 049745ae65d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoRTPSource.hh +++ /dev/null @@ -1,60 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// H.263+ Video RTP Sources -// C++ header - -#ifndef _H263_PLUS_VIDEO_RTP_SOURCE_HH -#define _H263_PLUS_VIDEO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -#define SPECIAL_HEADER_BUFFER_SIZE 1000 - -class H263plusVideoRTPSource: public MultiFramedRTPSource { -public: - static H263plusVideoRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency = 90000); - - // A data structure that stores copies of the special header bytes - // from the most recent frame's RTP packets: - unsigned char fNumSpecialHeaders; - unsigned fSpecialHeaderBytesLength; - unsigned char fSpecialHeaderBytes[SPECIAL_HEADER_BUFFER_SIZE]; - unsigned fPacketSizes[256]; - -protected: - virtual ~H263plusVideoRTPSource(); - -private: - H263plusVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoStreamFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoStreamFramer.hh deleted file mode 100644 index 80b650c78c0..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/H263plusVideoStreamFramer.hh +++ /dev/null @@ -1,64 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. -// A filter that breaks up an H263 video elementary stream into frames. -// Author Benhard Feiten - -#ifndef _H263PLUS_VIDEO_STREAM_FRAMER_HH -#define _H263PLUS_VIDEO_STREAM_FRAMER_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - - -class H263plusVideoStreamFramer: public FramedFilter { -public: - - static H263plusVideoStreamFramer* createNew(UsageEnvironment& env, FramedSource* inputSource); - - Boolean& pictureEndMarker() { return fPictureEndMarker; } // a hack for implementing the RTP 'M' bit - -protected: - // Constructor called only by createNew(), or by subclass constructors - H263plusVideoStreamFramer(UsageEnvironment& env, - FramedSource* inputSource, - Boolean createParser = True); - virtual ~H263plusVideoStreamFramer(); - - -public: - static void continueReadProcessing(void* clientData, - unsigned char* ptr, unsigned size, - struct timeval presentationTime); - void continueReadProcessing(); - -private: - virtual void doGetNextFrame(); - virtual Boolean isH263plusVideoStreamFramer() const; - -protected: - double fFrameRate; // Note: For MPEG-4, this is really a 'tick rate' ?? - unsigned fPictureCount; // hack used to implement doGetNextFrame() ?? - Boolean fPictureEndMarker; - -private: - class H263plusVideoStreamParser* fParser; - struct timeval fPresentationTimeBase; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/H264VideoRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/H264VideoRTPSource.hh deleted file mode 100644 index add3ee0440a..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/H264VideoRTPSource.hh +++ /dev/null @@ -1,72 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// H.264 Video RTP Sources -// C++ header - -#ifndef _H264_VIDEO_RTP_SOURCE_HH -#define _H264_VIDEO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -#define SPECIAL_HEADER_BUFFER_SIZE 1000 - -class H264VideoRTPSource: public MultiFramedRTPSource { -public: - static H264VideoRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency = 90000); - -private: - H264VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - - virtual ~H264VideoRTPSource(); - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; - -private: - friend class H264BufferedPacket; - unsigned char fCurPacketNALUnitType; -}; - -class SPropRecord { -public: - ~SPropRecord() { delete[] sPropBytes; } - - unsigned sPropLength; // in bytes - unsigned char* sPropBytes; -}; - -SPropRecord* parseSPropParameterSets(char const* sPropParameterSetsStr, - // result parameter: - unsigned& numSPropRecords); - // Returns the binary value of each 'parameter set' specified in a - // "sprop-parameter-sets" string (in the SDP description for a H.264/RTP stream). - // The value is returned as an array (length "numSPropRecords") of "SPropRecord"s. - // This array is dynamically allocated by this routine, and must be delete[]d by the caller. - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/HTTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/HTTPSink.hh deleted file mode 100644 index 84b50cc7ee7..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/HTTPSink.hh +++ /dev/null @@ -1,65 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// HTTP Sinks -// C++ header - -#ifndef _HTTP_SINK_HH -#define _HTTP_SINK_HH - -#ifndef _MEDIA_SINK_HH -#include "MediaSink.hh" -#endif -#ifndef _NET_ADDRESS_HH -#include "NetAddress.hh" -#endif - -class HTTPSink: public MediaSink { -public: - static HTTPSink* createNew(UsageEnvironment& env, Port ourPort); - // if ourPort.num() == 0, we'll choose (& return) port - -protected: - HTTPSink(UsageEnvironment& env, int ourSocket); // called only by createNew() - virtual ~HTTPSink(); - - virtual Boolean isUseableFrame(unsigned char* framePtr, unsigned frameSize); - // by default, True, but can be redefined by subclasses to select - // which frames get passed to the HTTP client. - -private: // redefined virtual functions: - virtual Boolean continuePlaying(); - -protected: - static int setUpOurSocket(UsageEnvironment& env, Port& ourPort); - static void appendPortNum(UsageEnvironment& env, Port const& port); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, struct timeval presentationTime); - - static void ourOnSourceClosure(void* clientData); - - int fSocket; - unsigned char fBuffer[10000]; // size should really be an attribute of source ##### - int fClientSocket; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/InputFile.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/InputFile.hh deleted file mode 100644 index 806fc642e0c..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/InputFile.hh +++ /dev/null @@ -1,41 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Common routines for opening/closing named input files -// C++ header - -#ifndef _INPUT_FILE_HH -#define _INPUT_FILE_HH - -#include -#include - -FILE* OpenInputFile(UsageEnvironment& env, char const* fileName); - -void CloseInputFile(FILE* fid); - -u_int64_t GetFileSize(char const* fileName, FILE* fid); - // 0 means zero-length, unbounded, or unknown - -u_int64_t SeekFile64(FILE *fid, int64_t offset, int whence); - // A platform-independent routine for seeking within (possibly) large files - -u_int64_t TellFile64(FILE *fid); - // A platform-independent routine for reporting the position within - // (possibly) large files - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoRTPSink.hh deleted file mode 100644 index 6c39d1b09b6..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoRTPSink.hh +++ /dev/null @@ -1,52 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for JPEG video (RFC 2435) -// C++ header - -#ifndef _JPEG_VIDEO_RTP_SINK_HH -#define _JPEG_VIDEO_RTP_SINK_HH - -#ifndef _VIDEO_RTP_SINK_HH -#include "VideoRTPSink.hh" -#endif - -class JPEGVideoRTPSink: public VideoRTPSink { -public: - static JPEGVideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs); - -protected: - JPEGVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs); - // called only by createNew() - - virtual ~JPEGVideoRTPSink(); - -private: // redefined virtual functions: - virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); - - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual - Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - virtual unsigned specialHeaderSize() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoRTPSource.hh deleted file mode 100644 index 226bf67d11c..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoRTPSource.hh +++ /dev/null @@ -1,54 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// JPEG Video (RFC 2435) RTP Sources -// C++ header - -#ifndef _JPEG_VIDEO_RTP_SOURCE_HH -#define _JPEG_VIDEO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -#define MAX_JPEG_HEADER_SIZE 1024 - -class JPEGVideoRTPSource: public MultiFramedRTPSource { -public: - static JPEGVideoRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat = 26, - unsigned rtpPayloadFrequency = 90000); - -protected: - virtual ~JPEGVideoRTPSource(); - -private: - JPEGVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - - virtual char const* MIMEtype() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoSource.hh deleted file mode 100644 index d116c4851c1..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/JPEGVideoSource.hh +++ /dev/null @@ -1,51 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// JPEG video sources -// C++ header - -#ifndef _JPEG_VIDEO_SOURCE_HH -#define _JPEG_VIDEO_SOURCE_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -class JPEGVideoSource: public FramedSource { -public: - virtual u_int8_t type() = 0; - virtual u_int8_t qFactor() = 0; - virtual u_int8_t width() = 0; // # pixels/8 (or 0 for 2048 pixels) - virtual u_int8_t height() = 0; // # pixels/8 (or 0 for 2048 pixels) - - virtual u_int8_t const* quantizationTables(u_int8_t& precision, - u_int16_t& length); - // If "qFactor()" returns a value >= 128, then this function is called - // to tell us the quantization tables that are being used. - // (The default implementation of this function just returns NULL.) - // "precision" and "length" are as defined in RFC 2435, section 3.1.8. - -protected: - JPEGVideoSource(UsageEnvironment& env); // abstract base class - virtual ~JPEGVideoSource(); - -private: - // redefined virtual functions: - virtual Boolean isJPEGVideoSource() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADU.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADU.hh deleted file mode 100644 index 6d146f61715..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADU.hh +++ /dev/null @@ -1,98 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// 'ADU' MP3 streams (for improved loss-tolerance) -// C++ header - -#ifndef _MP3_ADU_HH -#define _MP3_ADU_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - -class ADUFromMP3Source: public FramedFilter { -public: - static ADUFromMP3Source* createNew(UsageEnvironment& env, - FramedSource* inputSource, - Boolean includeADUdescriptors = True); - - void resetInput(); - // This is called whenever there's a discontinuity in the input MP3 source - // (e.g., due to seeking within the source). It causes any still-unprocessed - // MP3 frame data within our queue to be discarded, so that it does not - // erroneously get used by backpointers from the new MP3 frames. - - Boolean setScaleFactor(int scale); - -protected: - ADUFromMP3Source(UsageEnvironment& env, - FramedSource* inputSource, - Boolean includeADUdescriptors); - // called only by createNew() - virtual ~ADUFromMP3Source(); - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - virtual char const* MIMEtype() const; - -private: - Boolean doGetNextFrame1(); - -private: - Boolean fAreEnqueueingMP3Frame; - class SegmentQueue* fSegments; - Boolean fIncludeADUdescriptors; - unsigned fTotalDataSizeBeforePreviousRead; - int fScale; - unsigned fFrameCounter; -}; - -class MP3FromADUSource: public FramedFilter { -public: - static MP3FromADUSource* createNew(UsageEnvironment& env, - FramedSource* inputSource, - Boolean includeADUdescriptors = True); - -protected: - MP3FromADUSource(UsageEnvironment& env, - FramedSource* inputSource, - Boolean includeADUdescriptors); - // called only by createNew() - virtual ~MP3FromADUSource(); - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - virtual char const* MIMEtype() const; - -private: - Boolean needToGetAnADU(); - void insertDummyADUsIfNecessary(); - Boolean generateFrameFromHeadADU(); - -private: - Boolean fAreEnqueueingADU; - class SegmentQueue* fSegments; - Boolean fIncludeADUdescriptors; -}; - -// Definitions of external C functions that implement various MP3 operations: -extern "C" int mp3ZeroOutSideInfo(unsigned char*, unsigned, unsigned); - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADURTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADURTPSink.hh deleted file mode 100644 index a8c50646371..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADURTPSink.hh +++ /dev/null @@ -1,55 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for 'ADUized' MP3 frames ("mpa-robust") -// C++ header - -#ifndef _MP3_ADU_RTP_SINK_HH -#define _MP3_ADU_RTP_SINK_HH - -#ifndef _AUDIO_RTP_SINK_HH -#include "AudioRTPSink.hh" -#endif - -class MP3ADURTPSink: public AudioRTPSink { -public: - static MP3ADURTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char RTPPayloadType); - -protected: - virtual ~MP3ADURTPSink(); - -private: - MP3ADURTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char RTPPayloadType); - // called only by createNew() - - -private: - // Redefined virtual functions: - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual unsigned specialHeaderSize() const; - -private: - unsigned fCurADUSize; // used when fragmenting over multiple RTP packets -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADURTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADURTPSource.hh deleted file mode 100644 index caa9daaa22e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADURTPSource.hh +++ /dev/null @@ -1,49 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP source for 'ADUized' MP3 frames ("mpa-robust") -// C++ header - -#ifndef _MP3_ADU_SOURCE_HH -#define _MP3_ADU_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class MP3ADURTPSource: public MultiFramedRTPSource { -public: - static MP3ADURTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency = 90000); - -protected: - virtual ~MP3ADURTPSource(); - -private: - MP3ADURTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual char const* MIMEtype() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADUTranscoder.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADUTranscoder.hh deleted file mode 100644 index 110115bfb87..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADUTranscoder.hh +++ /dev/null @@ -1,64 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Transcoder for ADUized MP3 frames -// C++ header - -#ifndef _MP3_ADU_TRANSCODER_HH -#define _MP3_ADU_TRANSCODER_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - -class MP3ADUTranscoder: public FramedFilter { -public: - static MP3ADUTranscoder* createNew(UsageEnvironment& env, - unsigned outBitrate /* in kbps */, - FramedSource* inputSource); - - unsigned outBitrate() const { return fOutBitrate; } -protected: - MP3ADUTranscoder(UsageEnvironment& env, - unsigned outBitrate /* in kbps */, - FramedSource* inputSource); - // called only by createNew() - virtual ~MP3ADUTranscoder(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - virtual void getAttributes() const; - -private: - static void afterGettingFrame(void* clientData, - unsigned numBytesRead, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned numBytesRead, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - unsigned fOutBitrate; // in kbps - unsigned fAvailableBytesForBackpointer; - - unsigned char* fOrigADU; - // used to store incoming ADU prior to transcoding -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADUinterleaving.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADUinterleaving.hh deleted file mode 100644 index f80b9af5dc2..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3ADUinterleaving.hh +++ /dev/null @@ -1,129 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Interleaving of MP3 ADUs -// C++ header - -#ifndef _MP3_ADU_INTERLEAVING_HH -#define _MP3_ADU_INTERLEAVING_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - -// A data structure used to represent an interleaving -#define MAX_CYCLE_SIZE 256 -class Interleaving { -public: - Interleaving(unsigned cycleSize, unsigned char const* cycleArray); - virtual ~Interleaving(); - - unsigned cycleSize() const {return fCycleSize;} - unsigned char lookupInverseCycle(unsigned char index) const { - return fInverseCycle[index]; - } - -private: - unsigned fCycleSize; - unsigned char fInverseCycle[MAX_CYCLE_SIZE]; -}; - -// This class is used only as a base for the following two: - -class MP3ADUinterleaverBase: public FramedFilter { -protected: - MP3ADUinterleaverBase(UsageEnvironment& env, - FramedSource* inputSource); - // abstract base class - virtual ~MP3ADUinterleaverBase(); - - static FramedSource* getInputSource(UsageEnvironment& env, - char const* inputSourceName); - static void afterGettingFrame(void* clientData, - unsigned numBytesRead, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - virtual void afterGettingFrame(unsigned numBytesRead, - struct timeval presentationTime, - unsigned durationInMicroseconds) = 0; -}; - -// This class is used to convert an ADU sequence from non-interleaved -// to interleaved form: - -class MP3ADUinterleaver: public MP3ADUinterleaverBase { -public: - static MP3ADUinterleaver* createNew(UsageEnvironment& env, - Interleaving const& interleaving, - FramedSource* inputSource); - -protected: - MP3ADUinterleaver(UsageEnvironment& env, - Interleaving const& interleaving, - FramedSource* inputSource); - // called only by createNew() - virtual ~MP3ADUinterleaver(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - virtual void afterGettingFrame(unsigned numBytesRead, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - void releaseOutgoingFrame(); - -private: - Interleaving const fInterleaving; - class InterleavingFrames* fFrames; - unsigned char fPositionOfNextIncomingFrame; - unsigned fII, fICC; -}; - -// This class is used to convert an ADU sequence from interleaved -// to non-interleaved form: - -class MP3ADUdeinterleaver: public MP3ADUinterleaverBase { -public: - static MP3ADUdeinterleaver* createNew(UsageEnvironment& env, - FramedSource* inputSource); - -protected: - MP3ADUdeinterleaver(UsageEnvironment& env, - FramedSource* inputSource); - // called only by createNew() - virtual ~MP3ADUdeinterleaver(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - virtual void afterGettingFrame(unsigned numBytesRead, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - void releaseOutgoingFrame(); - -private: - class DeinterleavingFrames* fFrames; - unsigned fIIlastSeen, fICClastSeen; -}; - -#endif - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3AudioFileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3AudioFileServerMediaSubsession.hh deleted file mode 100644 index 87e03adca8d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3AudioFileServerMediaSubsession.hh +++ /dev/null @@ -1,66 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from an MP3 audio file. -// (Actually, any MPEG-1 or MPEG-2 audio file should work.) -// C++ header - -#ifndef _MP3_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH -#define _MP3_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#include "FileServerMediaSubsession.hh" -#endif -#ifndef _MP3_ADU_INTERLEAVING_HH -#include "MP3ADUinterleaving.hh" -#endif - -class MP3AudioFileServerMediaSubsession: public FileServerMediaSubsession{ -public: - static MP3AudioFileServerMediaSubsession* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource, - Boolean generateADUs, Interleaving* interleaving); - // Note: "interleaving" is used only if "generateADUs" is True, - // (and a value of NULL means 'no interleaving') - -private: - MP3AudioFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource, - Boolean generateADUs, - Interleaving* interleaving); - // called only by createNew(); - virtual ~MP3AudioFileServerMediaSubsession(); - -private: // redefined virtual functions - virtual void seekStreamSource(FramedSource* inputSource, float seekNPT); - virtual void setStreamSourceScale(FramedSource* inputSource, float scale); - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); - virtual void testScaleFactor(float& scale); - virtual float duration() const; - -private: - Boolean fGenerateADUs; - Interleaving* fInterleaving; - float fFileDuration; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3FileSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3FileSource.hh deleted file mode 100644 index 9bb0424e4b9..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3FileSource.hh +++ /dev/null @@ -1,65 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 File Sources -// C++ header - -#ifndef _MP3_FILE_SOURCE_HH -#define _MP3_FILE_SOURCE_HH - -#ifndef _FRAMED_FILE_SOURCE_HH -#include "FramedFileSource.hh" -#endif - -class MP3StreamState; // forward - -class MP3FileSource: public FramedFileSource { -public: - static MP3FileSource* createNew(UsageEnvironment& env, char const* fileName); - - float filePlayTime() const; - void setPresentationTimeScale(unsigned scale); - void seekWithinFile(float seekNPT); - -protected: - MP3FileSource(UsageEnvironment& env, FILE* fid); - // called only by createNew() - - virtual ~MP3FileSource(); - -protected: - void assignStream(FILE* fid, unsigned filesize); - Boolean initializeStream(); - - MP3StreamState* streamState() {return fStreamState;} - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - virtual char const* MIMEtype() const; - virtual void getAttributes() const; - -private: - virtual Boolean doGetNextFrame1(); - -private: - MP3StreamState* fStreamState; - Boolean fHaveJustInitialized; - struct timeval fFirstFramePresentationTime; // set on stream init -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3HTTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3HTTPSource.hh deleted file mode 100644 index 6c4bff927c3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3HTTPSource.hh +++ /dev/null @@ -1,48 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 HTTP Sources -// C++ header - -#ifndef _MP3_HTTP_SOURCE_HH -#define _MP3_HTTP_SOURCE_HH - -#ifndef _MP3_FILE_SOURCE_HH -#include "MP3FileSource.hh" -#endif -#ifndef _NET_ADDRESS_HH -#include "NetAddress.hh" -#endif - -class MP3HTTPSource: public MP3FileSource { -public: - static MP3HTTPSource* createNew(UsageEnvironment& env, - NetAddress const& address, Port port, - char const* remoteHostName, - char const* fileName); - - virtual ~MP3HTTPSource(); - -private: - MP3HTTPSource(UsageEnvironment& env, FILE* fid); - // called only by createNew() - - void writeGetCmd(char const* hostName, unsigned portNum, - char const* fileName); -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3Transcoder.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MP3Transcoder.hh deleted file mode 100644 index d538072e324..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MP3Transcoder.hh +++ /dev/null @@ -1,44 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP3 Transcoder -// C++ header - -#ifndef _MP3_TRANSCODER_HH -#define _MP3_TRANSCODER_HH - -#ifndef _MP3_ADU_HH -#include "MP3ADU.hh" -#endif -#ifndef _MP3_ADU_TRANSCODER_HH -#include "MP3ADUTranscoder.hh" -#endif - -class MP3Transcoder: public MP3FromADUSource { -public: - static MP3Transcoder* createNew(UsageEnvironment& env, - unsigned outBitrate /* in kbps */, - FramedSource* inputSource); - -protected: - MP3Transcoder(UsageEnvironment& env, - MP3ADUTranscoder* aduTranscoder); - // called only by createNew() - virtual ~MP3Transcoder(); -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioRTPSink.hh deleted file mode 100644 index 61920633f1f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioRTPSink.hh +++ /dev/null @@ -1,48 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for MPEG audio (RFC 2250) -// C++ header - -#ifndef _MPEG_1OR2_AUDIO_RTP_SINK_HH -#define _MPEG_1OR2_AUDIO_RTP_SINK_HH - -#ifndef _AUDIO_RTP_SINK_HH -#include "AudioRTPSink.hh" -#endif - -class MPEG1or2AudioRTPSink: public AudioRTPSink { -public: - static MPEG1or2AudioRTPSink* createNew(UsageEnvironment& env, - Groupsock* RTPgs); - -protected: - MPEG1or2AudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs); - // called only by createNew() - - virtual ~MPEG1or2AudioRTPSink(); - -private: // redefined virtual functions: - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual unsigned specialHeaderSize() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioRTPSource.hh deleted file mode 100644 index ae3548ed2fe..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioRTPSource.hh +++ /dev/null @@ -1,51 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG-1 or MPEG-2 Audio RTP Sources -// C++ header - -#ifndef _MPEG_1OR2_AUDIO_RTP_SOURCE_HH -#define _MPEG_1OR2_AUDIO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class MPEG1or2AudioRTPSource: public MultiFramedRTPSource { -public: - static MPEG1or2AudioRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat = 14, - unsigned rtpTimestampFrequency = 90000); - -protected: - virtual ~MPEG1or2AudioRTPSource(); - -private: - MPEG1or2AudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioStreamFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioStreamFramer.hh deleted file mode 100644 index 7ca5f293d67..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2AudioStreamFramer.hh +++ /dev/null @@ -1,70 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an MPEG (1,2) audio elementary stream into frames -// C++ header - -#ifndef _MPEG_1OR2_AUDIO_STREAM_FRAMER_HH -#define _MPEG_1OR2_AUDIO_STREAM_FRAMER_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - -class MPEG1or2AudioStreamFramer: public FramedFilter { -public: - static MPEG1or2AudioStreamFramer* - createNew(UsageEnvironment& env, FramedSource* inputSource, - Boolean syncWithInputSource = False); - // If "syncWithInputSource" is True, the stream's presentation time - // will be reset to that of the input source, whenever new data - // is read from it. - - void flushInput(); // called if there is a discontinuity (seeking) in the input - -private: - MPEG1or2AudioStreamFramer(UsageEnvironment& env, FramedSource* inputSource, - Boolean syncWithInputSource); - // called only by createNew() - virtual ~MPEG1or2AudioStreamFramer(); - - static void continueReadProcessing(void* clientData, - unsigned char* ptr, unsigned size, - struct timeval presentationTime); - void continueReadProcessing(); - - void resetPresentationTime(struct timeval newPresentationTime); - // useful if we're being synced with a separate (e.g., video) stream - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - void reset(); - struct timeval currentFramePlayTime() const; - -private: - Boolean fSyncWithInputSource; - struct timeval fNextFramePresentationTime; - -private: // parsing state - class MPEG1or2AudioStreamParser* fParser; - friend class MPEG1or2AudioStreamParser; // hack -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2Demux.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2Demux.hh deleted file mode 100644 index e6145d735bd..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2Demux.hh +++ /dev/null @@ -1,150 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Demultiplexer for a MPEG 1 or 2 Program Stream -// C++ header - -#ifndef _MPEG_1OR2_DEMUX_HH -#define _MPEG_1OR2_DEMUX_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -class MPEG1or2DemuxedElementaryStream; // forward - -class MPEG1or2Demux: public Medium { -public: - static MPEG1or2Demux* createNew(UsageEnvironment& env, - FramedSource* inputSource, - Boolean reclaimWhenLastESDies = False); - // If "reclaimWhenLastESDies" is True, the the demux is deleted when - // all "MPEG1or2DemuxedElementaryStream"s that we created get deleted. - - MPEG1or2DemuxedElementaryStream* newElementaryStream(u_int8_t streamIdTag); - - // Specialized versions of the above for audio and video: - MPEG1or2DemuxedElementaryStream* newAudioStream(); - MPEG1or2DemuxedElementaryStream* newVideoStream(); - - // A hack for getting raw, undemuxed PES packets from the Program Stream: - MPEG1or2DemuxedElementaryStream* newRawPESStream(); - - void getNextFrame(u_int8_t streamIdTag, - unsigned char* to, unsigned maxSize, - FramedSource::afterGettingFunc* afterGettingFunc, - void* afterGettingClientData, - FramedSource::onCloseFunc* onCloseFunc, - void* onCloseClientData); - // similar to FramedSource::getNextFrame(), except that it also - // takes a stream id tag as parameter. - - void stopGettingFrames(u_int8_t streamIdTag); - // similar to FramedSource::stopGettingFrames(), except that it also - // takes a stream id tag as parameter. - - static void handleClosure(void* clientData); - // This should be called (on ourself) if the source is discovered - // to be closed (i.e., no longer readable) - - FramedSource* inputSource() const { return fInputSource; } - - class SCR { - public: - SCR(); - - u_int8_t highBit; - u_int32_t remainingBits; - u_int16_t extension; - - Boolean isValid; - }; - SCR& lastSeenSCR() { return fLastSeenSCR; } - - unsigned char mpegVersion() const { return fMPEGversion; } - - void flushInput(); // should be called before any 'seek' on the underlying source - -private: - MPEG1or2Demux(UsageEnvironment& env, - FramedSource* inputSource, Boolean reclaimWhenLastESDies); - // called only by createNew() - virtual ~MPEG1or2Demux(); - - void registerReadInterest(u_int8_t streamIdTag, - unsigned char* to, unsigned maxSize, - FramedSource::afterGettingFunc* afterGettingFunc, - void* afterGettingClientData, - FramedSource::onCloseFunc* onCloseFunc, - void* onCloseClientData); - - Boolean useSavedData(u_int8_t streamIdTag, - unsigned char* to, unsigned maxSize, - FramedSource::afterGettingFunc* afterGettingFunc, - void* afterGettingClientData); - - static void continueReadProcessing(void* clientData, - unsigned char* ptr, unsigned size, - struct timeval presentationTime); - void continueReadProcessing(); - -private: - friend class MPEG1or2DemuxedElementaryStream; - void noteElementaryStreamDeletion(MPEG1or2DemuxedElementaryStream* es); - -private: - FramedSource* fInputSource; - SCR fLastSeenSCR; - unsigned char fMPEGversion; - - unsigned char fNextAudioStreamNumber; - unsigned char fNextVideoStreamNumber; - Boolean fReclaimWhenLastESDies; - unsigned fNumOutstandingESs; - - // A descriptor for each possible stream id tag: - typedef struct OutputDescriptor { - // input parameters - unsigned char* to; unsigned maxSize; - FramedSource::afterGettingFunc* fAfterGettingFunc; - void* afterGettingClientData; - FramedSource::onCloseFunc* fOnCloseFunc; - void* onCloseClientData; - - // output parameters - unsigned frameSize; struct timeval presentationTime; - class SavedData; // forward - SavedData* savedDataHead; - SavedData* savedDataTail; - unsigned savedDataTotalSize; - - // status parameters - Boolean isPotentiallyReadable; - Boolean isCurrentlyActive; - Boolean isCurrentlyAwaitingData; - } OutputDescriptor_t; - OutputDescriptor_t fOutput[256]; - - unsigned fNumPendingReads; - Boolean fHaveUndeliveredData; - -private: // parsing state - class MPEGProgramStreamParser* fParser; - friend class MPEGProgramStreamParser; // hack -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2DemuxedElementaryStream.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2DemuxedElementaryStream.hh deleted file mode 100644 index 3355c6e8b6e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2DemuxedElementaryStream.hh +++ /dev/null @@ -1,69 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A MPEG 1 or 2 Elementary Stream, demultiplexed from a Program Stream -// C++ header - -#ifndef _MPEG_1OR2_DEMUXED_ELEMENTARY_STREAM_HH -#define _MPEG_1OR2_DEMUXED_ELEMENTARY_STREAM_HH - -#ifndef _MPEG_1OR2_DEMUX_HH -#include "MPEG1or2Demux.hh" -#endif - -class MPEG1or2DemuxedElementaryStream: public FramedSource { -public: - MPEG1or2Demux::SCR lastSeenSCR() const { return fLastSeenSCR; } - - unsigned char mpegVersion() const { return fMPEGversion; } - - MPEG1or2Demux& sourceDemux() const { return fOurSourceDemux; } - -private: // We are created only by a MPEG1or2Demux (a friend) - MPEG1or2DemuxedElementaryStream(UsageEnvironment& env, - u_int8_t streamIdTag, - MPEG1or2Demux& sourceDemux); - virtual ~MPEG1or2DemuxedElementaryStream(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - virtual void doStopGettingFrames(); - virtual char const* MIMEtype() const; - virtual unsigned maxFrameSize() const; - -private: - static void afterGettingFrame(void* clientData, - unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - - void afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - u_int8_t fOurStreamIdTag; - MPEG1or2Demux& fOurSourceDemux; - char const* fMIMEtype; - MPEG1or2Demux::SCR fLastSeenSCR; - unsigned char fMPEGversion; - - friend class MPEG1or2Demux; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2DemuxedServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2DemuxedServerMediaSubsession.hh deleted file mode 100644 index 911ace71c17..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2DemuxedServerMediaSubsession.hh +++ /dev/null @@ -1,63 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-1 or 2 demuxer. -// C++ header - -#ifndef _MPEG_1OR2_DEMUXED_SERVER_MEDIA_SUBSESSION_HH -#define _MPEG_1OR2_DEMUXED_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH -#include "OnDemandServerMediaSubsession.hh" -#endif -#ifndef _MPEG_1OR2_FILE_SERVER_DEMUX_HH -#include "MPEG1or2FileServerDemux.hh" -#endif - -class MPEG1or2DemuxedServerMediaSubsession: public OnDemandServerMediaSubsession{ -public: - static MPEG1or2DemuxedServerMediaSubsession* - createNew(MPEG1or2FileServerDemux& demux, u_int8_t streamIdTag, - Boolean reuseFirstSource, - Boolean iFramesOnly = False, double vshPeriod = 5.0); - // The last two parameters are relevant for video streams only - -private: - MPEG1or2DemuxedServerMediaSubsession(MPEG1or2FileServerDemux& demux, - u_int8_t streamIdTag, Boolean reuseFirstSource, - Boolean iFramesOnly, double vshPeriod); - // called only by createNew(); - virtual ~MPEG1or2DemuxedServerMediaSubsession(); - -private: // redefined virtual functions - virtual void seekStreamSource(FramedSource* inputSource, float seekNPT); - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); - virtual float duration() const; - -private: - MPEG1or2FileServerDemux& fOurDemux; - u_int8_t fStreamIdTag; - Boolean fIFramesOnly; // for video streams - double fVSHPeriod; // for video streams -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2FileServerDemux.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2FileServerDemux.hh deleted file mode 100644 index e6588243cd4..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2FileServerDemux.hh +++ /dev/null @@ -1,67 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A server demultiplexer for a MPEG 1 or 2 Program Stream -// C++ header - -#ifndef _MPEG_1OR2_FILE_SERVER_DEMUX_HH -#define _MPEG_1OR2_FILE_SERVER_DEMUX_HH - -#ifndef _SERVER_MEDIA_SESSION_HH -#include "ServerMediaSession.hh" -#endif -#ifndef _MPEG_1OR2_DEMUXED_ELEMENTARY_STREAM_HH -#include "MPEG1or2DemuxedElementaryStream.hh" -#endif - -class MPEG1or2FileServerDemux: public Medium { -public: - static MPEG1or2FileServerDemux* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); - - ServerMediaSubsession* newAudioServerMediaSubsession(); // MPEG-1 or 2 audio - ServerMediaSubsession* newVideoServerMediaSubsession(Boolean iFramesOnly = False, - double vshPeriod = 5.0 - /* how often (in seconds) to inject a Video_Sequence_Header, - if one doesn't already appear in the stream */); - ServerMediaSubsession* newAC3AudioServerMediaSubsession(); // AC-3 audio (from VOB) - - unsigned fileSize() const { return fFileSize; } - float fileDuration() const { return fFileDuration; } - -private: - MPEG1or2FileServerDemux(UsageEnvironment& env, char const* fileName, - Boolean reuseFirstSource); - // called only by createNew(); - virtual ~MPEG1or2FileServerDemux(); - -private: - friend class MPEG1or2DemuxedServerMediaSubsession; - MPEG1or2DemuxedElementaryStream* newElementaryStream(unsigned clientSessionId, - u_int8_t streamIdTag); - -private: - char const* fFileName; - unsigned fFileSize; - float fFileDuration; - Boolean fReuseFirstSource; - MPEG1or2Demux* fSession0Demux; - MPEG1or2Demux* fLastCreatedDemux; - u_int8_t fLastClientSessionId; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoFileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoFileServerMediaSubsession.hh deleted file mode 100644 index 08dfc5f3035..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoFileServerMediaSubsession.hh +++ /dev/null @@ -1,59 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-1 or 2 Elementary Stream video file. -// C++ header - -#ifndef _MPEG_1OR2_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH -#define _MPEG_1OR2_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#include "FileServerMediaSubsession.hh" -#endif - -class MPEG1or2VideoFileServerMediaSubsession: public FileServerMediaSubsession{ -public: - static MPEG1or2VideoFileServerMediaSubsession* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource, - Boolean iFramesOnly = False, - double vshPeriod = 5.0 - /* how often (in seconds) to inject a Video_Sequence_Header, - if one doesn't already appear in the stream */); - -private: - MPEG1or2VideoFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource, - Boolean iFramesOnly, - double vshPeriod); - // called only by createNew(); - virtual ~MPEG1or2VideoFileServerMediaSubsession(); - -private: // redefined virtual functions - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); - -private: - Boolean fIFramesOnly; - double fVSHPeriod; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoHTTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoHTTPSink.hh deleted file mode 100644 index 76d0f78039e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoHTTPSink.hh +++ /dev/null @@ -1,45 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A HTTP Sink specifically for MPEG Video -// C++ header - -#ifndef _MPEG_1OR2_VIDEO_HTTP_SINK_HH -#define _MPEG_1OR2_VIDEO_HTTP_SINK_HH - -#ifndef _HTTP_SINK_HH -#include "HTTPSink.hh" -#endif - -class MPEG1or2VideoHTTPSink: public HTTPSink { -public: - static MPEG1or2VideoHTTPSink* createNew(UsageEnvironment& env, Port ourPort); - // if ourPort.num() == 0, we'll choose (& return) port - -protected: - MPEG1or2VideoHTTPSink(UsageEnvironment& env, int ourSocket); - // called only by createNew() - virtual ~MPEG1or2VideoHTTPSink(); - -private: // redefined virtual functions: - virtual Boolean isUseableFrame(unsigned char* framePtr, unsigned frameSize); - -private: - Boolean fHaveSeenFirstVSH; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoRTPSink.hh deleted file mode 100644 index a6129a50fe6..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoRTPSink.hh +++ /dev/null @@ -1,69 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for MPEG video (RFC 2250) -// C++ header - -#ifndef _MPEG_1OR2_VIDEO_RTP_SINK_HH -#define _MPEG_1OR2_VIDEO_RTP_SINK_HH - -#ifndef _VIDEO_RTP_SINK_HH -#include "VideoRTPSink.hh" -#endif - -class MPEG1or2VideoRTPSink: public VideoRTPSink { -public: - static MPEG1or2VideoRTPSink* createNew(UsageEnvironment& env, Groupsock* RTPgs); - -protected: - MPEG1or2VideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs); - // called only by createNew() - - virtual ~MPEG1or2VideoRTPSink(); - -private: // redefined virtual functions: - virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); - - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual Boolean allowFragmentationAfterStart() const; - virtual - Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - virtual unsigned specialHeaderSize() const; - -private: - // MPEG video-specific state, used to decide how to fill out the - // video-specific header, and when to include multiple 'frames' in a - // single outgoing RTP packet. Eventually we should somehow get this - // state from the source (MPEG1or2VideoStreamFramer) instead, as the source - // already has this info itself. - struct { - unsigned temporal_reference; - unsigned char picture_coding_type; - unsigned char vector_code_bits; // FBV,BFC,FFV,FFC from RFC 2250, sec. 3.4 - } fPictureState; - Boolean fPreviousFrameWasSlice; - // used to implement frameCanAppearAfterPacketStart() - Boolean fSequenceHeaderPresent; - Boolean fPacketBeginsSlice, fPacketEndsSlice; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoRTPSource.hh deleted file mode 100644 index 9c59a6376bc..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoRTPSource.hh +++ /dev/null @@ -1,53 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG-1 or MPEG-2 Video RTP Sources -// C++ header - -#ifndef _MPEG_1OR2_VIDEO_RTP_SOURCE_HH -#define _MPEG_1OR2_VIDEO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class MPEG1or2VideoRTPSource: public MultiFramedRTPSource { -public: - static MPEG1or2VideoRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat = 32, - unsigned rtpPayloadFrequency = 90000); - -protected: - virtual ~MPEG1or2VideoRTPSource(); - -private: - MPEG1or2VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual Boolean packetIsUsableInJitterCalculation(unsigned char* packet, - unsigned packetSize); - virtual char const* MIMEtype() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoStreamDiscreteFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoStreamDiscreteFramer.hh deleted file mode 100644 index 093a183e450..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoStreamDiscreteFramer.hh +++ /dev/null @@ -1,74 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simplified version of "MPEG1or2VideoStreamFramer" that takes only -// complete, discrete frames (rather than an arbitrary byte stream) as input. -// This avoids the parsing and data copying overhead of the full -// "MPEG1or2VideoStreamFramer". -// C++ header - -#ifndef _MPEG1or2_VIDEO_STREAM_DISCRETE_FRAMER_HH -#define _MPEG1or2_VIDEO_STREAM_DISCRETE_FRAMER_HH - -#ifndef _MPEG1or2_VIDEO_STREAM_FRAMER_HH -#include "MPEG1or2VideoStreamFramer.hh" -#endif - -#define VSH_MAX_SIZE 1000 - -class MPEG1or2VideoStreamDiscreteFramer: public MPEG1or2VideoStreamFramer { -public: - static MPEG1or2VideoStreamDiscreteFramer* - createNew(UsageEnvironment& env, FramedSource* inputSource, - Boolean iFramesOnly = False, - double vshPeriod = 5.0); // see MPEG1or2VideoStreamFramer.hh - -private: - MPEG1or2VideoStreamDiscreteFramer(UsageEnvironment& env, - FramedSource* inputSource, - Boolean iFramesOnly, double vshPeriod); - // called only by createNew() - virtual ~MPEG1or2VideoStreamDiscreteFramer(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - struct timeval fLastNonBFramePresentationTime; - unsigned fLastNonBFrameTemporal_reference; - - // A saved copy of the most recently seen 'video_sequence_header', - // in case we need to insert it into the stream periodically: - unsigned char fSavedVSHBuffer[VSH_MAX_SIZE]; - unsigned fSavedVSHSize; - double fSavedVSHTimestamp; - Boolean fIFramesOnly; - double fVSHPeriod; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoStreamFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoStreamFramer.hh deleted file mode 100644 index 172c379adb3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG1or2VideoStreamFramer.hh +++ /dev/null @@ -1,56 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an MPEG 1 or 2 video elementary stream into -// frames for: Video_Sequence_Header, GOP_Header, Picture_Header -// C++ header - -#ifndef _MPEG_1OR2_VIDEO_STREAM_FRAMER_HH -#define _MPEG_1OR2_VIDEO_STREAM_FRAMER_HH - -#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH -#include "MPEGVideoStreamFramer.hh" -#endif - -class MPEG1or2VideoStreamFramer: public MPEGVideoStreamFramer { -public: - static MPEG1or2VideoStreamFramer* - createNew(UsageEnvironment& env, FramedSource* inputSource, - Boolean iFramesOnly = False, - double vshPeriod = 5.0 - /* how often (in seconds) to inject a Video_Sequence_Header, - if one doesn't already appear in the stream */); - -protected: - MPEG1or2VideoStreamFramer(UsageEnvironment& env, - FramedSource* inputSource, - Boolean iFramesOnly, double vshPeriod, - Boolean createParser = True); - // called only by createNew(), or by subclass constructors - virtual ~MPEG1or2VideoStreamFramer(); - -private: - // redefined virtual functions: - virtual Boolean isMPEG1or2VideoStreamFramer() const; - -private: - double getCurrentPTS() const; - - friend class MPEG1or2VideoStreamParser; // hack -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportFileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportFileServerMediaSubsession.hh deleted file mode 100644 index a58e659b978..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportFileServerMediaSubsession.hh +++ /dev/null @@ -1,49 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-2 Transport Stream file. -// C++ header - -#ifndef _MPEG2_TRANSPORT_FILE_SERVER_MEDIA_SUBSESSION_HH -#define _MPEG2_TRANSPORT_FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#include "FileServerMediaSubsession.hh" -#endif - -class MPEG2TransportFileServerMediaSubsession: public FileServerMediaSubsession{ -public: - static MPEG2TransportFileServerMediaSubsession* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); - -protected: - MPEG2TransportFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, - Boolean reuseFirstSource); - // called only by createNew(); - virtual ~MPEG2TransportFileServerMediaSubsession(); - -private: // redefined virtual functions - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFramer.hh deleted file mode 100644 index 526ed665dbe..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFramer.hh +++ /dev/null @@ -1,50 +0,0 @@ -// A filter that passes through (unchanged) chunks that contain an integral number -// of MPEG-2 Transport Stream packets, but returning (in "fDurationInMicroseconds") -// an updated estimate of the time gap between chunks. -// C++ header - -#ifndef _MPEG2_TRANSPORT_STREAM_FRAMER_HH -#define _MPEG2_TRANSPORT_STREAM_FRAMER_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - -#ifndef _HASH_TABLE_HH -#include "HashTable.hh" -#endif - -class MPEG2TransportStreamFramer: public FramedFilter { -public: - static MPEG2TransportStreamFramer* - createNew(UsageEnvironment& env, FramedSource* inputSource); - - unsigned long tsPacketCount() const { return fTSPacketCount; } - -protected: - MPEG2TransportStreamFramer(UsageEnvironment& env, FramedSource* inputSource); - // called only by createNew() - virtual ~MPEG2TransportStreamFramer(); - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - virtual void doStopGettingFrames(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - struct timeval presentationTime); - - void updateTSPacketDurationEstimate(unsigned char* pkt, double timeNow); - -private: - unsigned long fTSPacketCount; - double fTSPacketDurationEstimate; - HashTable* fPIDStatusTable; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFromESSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFromESSource.hh deleted file mode 100644 index ca5acd12548..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFromESSource.hh +++ /dev/null @@ -1,57 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter for converting one or more MPEG Elementary Streams -// to a MPEG-2 Transport Stream -// C++ header - -#ifndef _MPEG2_TRANSPORT_STREAM_FROM_ES_SOURCE_HH -#define _MPEG2_TRANSPORT_STREAM_FROM_ES_SOURCE_HH - -#ifndef _MPEG2_TRANSPORT_STREAM_MULTIPLEXOR_HH -#include "MPEG2TransportStreamMultiplexor.hh" -#endif - -class MPEG2TransportStreamFromESSource: public MPEG2TransportStreamMultiplexor { -public: - static MPEG2TransportStreamFromESSource* createNew(UsageEnvironment& env); - - void addNewVideoSource(FramedSource* inputSource, int mpegVersion); - void addNewAudioSource(FramedSource* inputSource, int mpegVersion); - -protected: - MPEG2TransportStreamFromESSource(UsageEnvironment& env); - // called only by createNew() - virtual ~MPEG2TransportStreamFromESSource(); - -private: - // Redefined virtual functions: - virtual void doStopGettingFrames(); - virtual void awaitNewBuffer(unsigned char* oldBuffer); - -private: - void addNewInputSource(FramedSource* inputSource, - u_int8_t streamId, int mpegVersion); - // used to implement addNew*Source() above - -private: - friend class InputESSourceRecord; - class InputESSourceRecord* fInputSources; - unsigned fVideoSourceCounter, fAudioSourceCounter; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFromPESSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFromPESSource.hh deleted file mode 100644 index 6ba39362945..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamFromPESSource.hh +++ /dev/null @@ -1,62 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter for converting a stream of MPEG PES packets to a MPEG-2 Transport Stream -// C++ header - -#ifndef _MPEG2_TRANSPORT_STREAM_FROM_PES_SOURCE_HH -#define _MPEG2_TRANSPORT_STREAM_FROM_PES_SOURCE_HH - -#ifndef _MPEG2_TRANSPORT_STREAM_MULTIPLEXOR_HH -#include "MPEG2TransportStreamMultiplexor.hh" -#endif -#ifndef _MPEG_1OR2_DEMUXED_ELEMENTARY_STREAM_HH -#include "MPEG1or2DemuxedElementaryStream.hh" -#endif - -class MPEG2TransportStreamFromPESSource: public MPEG2TransportStreamMultiplexor { -public: - static MPEG2TransportStreamFromPESSource* - createNew(UsageEnvironment& env, MPEG1or2DemuxedElementaryStream* inputSource); - -protected: - MPEG2TransportStreamFromPESSource(UsageEnvironment& env, - MPEG1or2DemuxedElementaryStream* inputSource); - // called only by createNew() - virtual ~MPEG2TransportStreamFromPESSource(); - -private: - // Redefined virtual functions: - virtual void doStopGettingFrames(); - virtual void awaitNewBuffer(unsigned char* oldBuffer); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - MPEG1or2DemuxedElementaryStream* fInputSource; - unsigned char* fInputBuffer; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamMultiplexor.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamMultiplexor.hh deleted file mode 100644 index 0d3eff22ec2..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG2TransportStreamMultiplexor.hh +++ /dev/null @@ -1,78 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A class for generating MPEG-2 Transport Stream from one or more input -// Elementary Stream data sources -// C++ header - -#ifndef _MPEG2_TRANSPORT_STREAM_MULTIPLEXOR_HH -#define _MPEG2_TRANSPORT_STREAM_MULTIPLEXOR_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif -#ifndef _MPEG_1OR2_DEMUX_HH -#include "MPEG1or2Demux.hh" // for SCR -#endif - -#define PID_TABLE_SIZE 256 - -class MPEG2TransportStreamMultiplexor: public FramedSource { -protected: - MPEG2TransportStreamMultiplexor(UsageEnvironment& env); - virtual ~MPEG2TransportStreamMultiplexor(); - - virtual void awaitNewBuffer(unsigned char* oldBuffer) = 0; - // implemented by subclasses - - void handleNewBuffer(unsigned char* buffer, unsigned bufferSize, - int mpegVersion, MPEG1or2Demux::SCR scr); - // called by "awaitNewBuffer()" - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - -private: - void deliverDataToClient(u_int8_t pid, unsigned char* buffer, unsigned bufferSize, - unsigned& startPositionInBuffer); - - void deliverPATPacket(); - void deliverPMTPacket(Boolean hasChanged); - - void setProgramStreamMap(unsigned frameSize); - -protected: - Boolean fHaveVideoStreams; - -private: - unsigned fOutgoingPacketCounter; - unsigned fProgramMapVersion; - u_int8_t fPreviousInputProgramMapVersion, fCurrentInputProgramMapVersion; - // These two fields are used if we see "program_stream_map"s in the input. - struct { - unsigned counter; - u_int8_t streamType; // for use in Program Maps - } fPIDState[PID_TABLE_SIZE]; - u_int8_t fPCR_PID, fCurrentPID; - // Note: We map 8-bit stream_ids directly to PIDs - MPEG1or2Demux::SCR fPCR; - unsigned char* fInputBuffer; - unsigned fInputBufferSize, fInputBufferBytesUsed; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4ESVideoRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4ESVideoRTPSink.hh deleted file mode 100644 index 6ce4b9a1a1f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4ESVideoRTPSink.hh +++ /dev/null @@ -1,63 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for MPEG-4 Elementary Stream video (RFC 3016) -// C++ header - -#ifndef _MPEG4ES_VIDEO_RTP_SINK_HH -#define _MPEG4ES_VIDEO_RTP_SINK_HH - -#ifndef _VIDEO_RTP_SINK_HH -#include "VideoRTPSink.hh" -#endif - -class MPEG4ESVideoRTPSink: public VideoRTPSink { -public: - static MPEG4ESVideoRTPSink* createNew(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency = 90000); - -protected: - MPEG4ESVideoRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency); - // called only by createNew() - - virtual ~MPEG4ESVideoRTPSink(); - -private: // redefined virtual functions: - virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); - - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual Boolean allowFragmentationAfterStart() const; - virtual Boolean - frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - - virtual char const* auxSDPLine(); - -private: - Boolean fVOPIsPresent; - char* fAuxSDPLine; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4ESVideoRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4ESVideoRTPSource.hh deleted file mode 100644 index ff02e2f2509..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4ESVideoRTPSource.hh +++ /dev/null @@ -1,51 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MP4V-ES video RTP stream sources -// C++ header - -#ifndef _MPEG4_ES_VIDEO_RTP_SOURCE_HH -#define _MPEG4_ES_VIDEO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class MPEG4ESVideoRTPSource: public MultiFramedRTPSource { -public: - static MPEG4ESVideoRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - -protected: - virtual ~MPEG4ESVideoRTPSource(); - -private: - MPEG4ESVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4GenericRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4GenericRTPSink.hh deleted file mode 100644 index 67c5b4b3800..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4GenericRTPSink.hh +++ /dev/null @@ -1,70 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG4-GENERIC ("audio", "video", or "application") RTP stream sinks -// C++ header - -#ifndef _MPEG4_GENERIC_RTP_SINK_HH -#define _MPEG4_GENERIC_RTP_SINK_HH - -#ifndef _MULTI_FRAMED_RTP_SINK_HH -#include "MultiFramedRTPSink.hh" -#endif - -class MPEG4GenericRTPSink: public MultiFramedRTPSink { -public: - static MPEG4GenericRTPSink* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, u_int32_t rtpTimestampFrequency, - char const* sdpMediaTypeString, char const* mpeg4Mode, - char const* configString, - unsigned numChannels = 1); - -protected: - MPEG4GenericRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - u_int8_t rtpPayloadFormat, - u_int32_t rtpTimestampFrequency, - char const* sdpMediaTypeString, - char const* mpeg4Mode, char const* configString, - unsigned numChannels); - // called only by createNew() - - virtual ~MPEG4GenericRTPSink(); - -private: // redefined virtual functions: - virtual - Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual unsigned specialHeaderSize() const; - - virtual char const* sdpMediaType() const; - - virtual char const* auxSDPLine(); // for the "a=fmtp:" SDP line - -private: - char const* fSDPMediaTypeString; - char const* fMPEG4Mode; - char const* fConfigString; - char* fFmtpSDPLine; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4GenericRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4GenericRTPSource.hh deleted file mode 100644 index cfb52cb6eb7..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4GenericRTPSource.hh +++ /dev/null @@ -1,82 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG4-GENERIC ("audio", "video", or "application") RTP stream sources -// C++ header - -#ifndef _MPEG4_GENERIC_RTP_SOURCE_HH -#define _MPEG4_GENERIC_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -#define SPECIAL_HEADER_BUFFER_SIZE 1000 - -class MPEG4GenericRTPSource: public MultiFramedRTPSource { -public: - static MPEG4GenericRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mediumName, - char const* mode, unsigned sizeLength, unsigned indexLength, - unsigned indexDeltaLength - // add other parameters later - ); - // mediumName is "audio", "video", or "application" - // it *cannot* be NULL - -protected: - virtual ~MPEG4GenericRTPSource(); - -private: - MPEG4GenericRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mediumName, - char const* mode, - unsigned sizeLength, unsigned indexLength, - unsigned indexDeltaLength - ); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; - -private: - char* fMIMEType; - - char* fMode; - unsigned fSizeLength, fIndexLength, fIndexDeltaLength; - unsigned fNumAUHeaders; // in the most recently read packet - unsigned fNextAUHeader; // index of the next AU Header to read - struct AUHeader* fAUHeaders; - - friend class MPEG4GenericBufferedPacket; -}; - - - -// A function that looks up the sampling frequency from an -// "AudioSpecificConfig" string. (0 means 'unknown') -unsigned samplingFrequencyFromAudioSpecificConfig(char const* configStr); - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4LATMAudioRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4LATMAudioRTPSink.hh deleted file mode 100644 index b317afd1d4f..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4LATMAudioRTPSink.hh +++ /dev/null @@ -1,69 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for MPEG-4 audio, using LATM multiplexing (RFC 3016) -// (Note that the initial 'size' field is assumed to be present at the start of -// each frame.) -// C++ header - -#ifndef _MPEG4_LATM_AUDIO_RTP_SINK_HH -#define _MPEG4_LATM_AUDIO_RTP_SINK_HH - -#ifndef _AUDIO_RTP_SINK_HH -#include "AudioRTPSink.hh" -#endif - -class MPEG4LATMAudioRTPSink: public AudioRTPSink { -public: - static MPEG4LATMAudioRTPSink* createNew(UsageEnvironment& env, - Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency, - char const* streamMuxConfigString, - unsigned numChannels, - Boolean allowMultipleFramesPerPacket = False); - -protected: - MPEG4LATMAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - u_int32_t rtpTimestampFrequency, - char const* streamMuxConfigString, - unsigned numChannels, - Boolean allowMultipleFramesPerPacket); - // called only by createNew() - - virtual ~MPEG4LATMAudioRTPSink(); - -private: // redefined virtual functions: - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual Boolean - frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - - virtual char const* auxSDPLine(); // for the "a=fmtp:" SDP line - -private: - char const* fStreamMuxConfigString; - char* fFmtpSDPLine; - Boolean fAllowMultipleFramesPerPacket; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4LATMAudioRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4LATMAudioRTPSource.hh deleted file mode 100644 index 6d35f7cf1df..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4LATMAudioRTPSource.hh +++ /dev/null @@ -1,101 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// MPEG-4 audio, using LATM multiplexing -// C++ header - -#ifndef _MPEG4_LATM_AUDIO_RTP_SOURCE_HH -#define _MPEG4_LATM_AUDIO_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class MPEG4LATMAudioRTPSource: public MultiFramedRTPSource { -public: - static MPEG4LATMAudioRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - - // By default, the LATM data length field is included at the beginning of each - // returned frame. To omit this field, call the following: - void omitLATMDataLengthField(); - - Boolean returnedFrameIncludesLATMDataLengthField() const { return fIncludeLATMDataLengthField; } - -protected: - virtual ~MPEG4LATMAudioRTPSource(); - -private: - MPEG4LATMAudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; - -private: - Boolean fIncludeLATMDataLengthField; -}; - - -// A utility for parsing a "StreamMuxConfig" string -Boolean -parseStreamMuxConfigStr(char const* configStr, - // result parameters: - Boolean& audioMuxVersion, - Boolean& allStreamsSameTimeFraming, - unsigned char& numSubFrames, - unsigned char& numProgram, - unsigned char& numLayer, - unsigned char*& audioSpecificConfig, - unsigned& audioSpecificConfigSize); - // Parses "configStr" as a sequence of hexadecimal digits, representing - // a "StreamMuxConfig" (as defined in ISO.IEC 14496-3, table 1.21). - // Returns, in "audioSpecificConfig", a binary representation of - // the enclosed "AudioSpecificConfig" structure (of size - // "audioSpecificConfigSize" bytes). The memory for this is allocated - // dynamically by this function; the caller is responsible for - // freeing it. Other values, that precede "AudioSpecificConfig", - // are returned in the other parameters. - // Returns True iff the parsing succeeds. - // IMPORTANT NOTE: The implementation of this function currently assumes - // that everything after the first "numLayer" field is an - // "AudioSpecificConfig". Therefore, it will not work properly if - // "audioMuxVersion" != 0, "numProgram" > 0, or "numLayer" > 0. - // Also, any 'other data' or CRC info will be included at - // the end of "audioSpecificConfig". - -unsigned char* parseStreamMuxConfigStr(char const* configStr, - // result parameter: - unsigned& audioSpecificConfigSize); - // A variant of the above that returns just the "AudioSpecificConfig" data - // (or NULL) if the parsing failed, without bothering with the other - // result parameters. - -unsigned char* parseGeneralConfigStr(char const* configStr, - // result parameter: - unsigned& configSize); - // A routine that parses an arbitrary config string, returning - // the result in binary form. - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoFileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoFileServerMediaSubsession.hh deleted file mode 100644 index 9c73dfb5e06..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoFileServerMediaSubsession.hh +++ /dev/null @@ -1,60 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from a MPEG-4 video file. -// C++ header - -#ifndef _MPEG4_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH -#define _MPEG4_VIDEO_FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#include "FileServerMediaSubsession.hh" -#endif - -class MPEG4VideoFileServerMediaSubsession: public FileServerMediaSubsession{ -public: - static MPEG4VideoFileServerMediaSubsession* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource); - - // Used to implement "getAuxSDPLine()": - void checkForAuxSDPLine1(); - void afterPlayingDummy1(); - -private: - MPEG4VideoFileServerMediaSubsession(UsageEnvironment& env, - char const* fileName, Boolean reuseFirstSource); - // called only by createNew(); - virtual ~MPEG4VideoFileServerMediaSubsession(); - - void setDoneFlag() { fDoneFlag = ~0; } - -private: // redefined virtual functions - virtual char const* getAuxSDPLine(RTPSink* rtpSink, - FramedSource* inputSource); - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); - -private: - char fDoneFlag; // used when setting up "fSDPLines" - RTPSink* fDummyRTPSink; // ditto -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoStreamDiscreteFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoStreamDiscreteFramer.hh deleted file mode 100644 index 237d8c07fef..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoStreamDiscreteFramer.hh +++ /dev/null @@ -1,70 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simplified version of "MPEG4VideoStreamFramer" that takes only complete, -// discrete frames (rather than an arbitrary byte stream) as input. -// This avoids the parsing and data copying overhead of the full -// "MPEG4VideoStreamFramer". -// C++ header - -#ifndef _MPEG4_VIDEO_STREAM_DISCRETE_FRAMER_HH -#define _MPEG4_VIDEO_STREAM_DISCRETE_FRAMER_HH - -#ifndef _MPEG4_VIDEO_STREAM_FRAMER_HH -#include "MPEG4VideoStreamFramer.hh" -#endif - -class MPEG4VideoStreamDiscreteFramer: public MPEG4VideoStreamFramer { -public: - static MPEG4VideoStreamDiscreteFramer* - createNew(UsageEnvironment& env, FramedSource* inputSource); - -private: - MPEG4VideoStreamDiscreteFramer(UsageEnvironment& env, - FramedSource* inputSource); - // called only by createNew() - virtual ~MPEG4VideoStreamDiscreteFramer(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - - Boolean getNextFrameBit(u_int8_t& result); - Boolean getNextFrameBits(unsigned numBits, u_int32_t& result); - // Which are used by: - void analyzeVOLHeader(); - -private: - unsigned fNumBitsSeenSoFar; // used by the getNextFrameBit*() routines - u_int32_t vop_time_increment_resolution; - unsigned fNumVTIRBits; - // # of bits needed to count to "vop_time_increment_resolution" - struct timeval fLastNonBFramePresentationTime; - unsigned fLastNonBFrameVop_time_increment; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoStreamFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoStreamFramer.hh deleted file mode 100644 index 43f8ba15721..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEG4VideoStreamFramer.hh +++ /dev/null @@ -1,71 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an MPEG-4 video elementary stream into -// frames for: -// - Visual Object Sequence (VS) Header + Visual Object (VO) Header -// + Video Object Layer (VOL) Header -// - Group of VOP (GOV) Header -// - VOP frame -// C++ header - -#ifndef _MPEG4_VIDEO_STREAM_FRAMER_HH -#define _MPEG4_VIDEO_STREAM_FRAMER_HH - -#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH -#include "MPEGVideoStreamFramer.hh" -#endif - -class MPEG4VideoStreamFramer: public MPEGVideoStreamFramer { -public: - static MPEG4VideoStreamFramer* - createNew(UsageEnvironment& env, FramedSource* inputSource); - - u_int8_t profile_and_level_indication() const { - return fProfileAndLevelIndication; - } - - unsigned char* getConfigBytes(unsigned& numBytes) const; - -protected: - MPEG4VideoStreamFramer(UsageEnvironment& env, - FramedSource* inputSource, - Boolean createParser = True); - // called only by createNew(), or by subclass constructors - virtual ~MPEG4VideoStreamFramer(); - - void startNewConfig(); - void appendToNewConfig(unsigned char* newConfigBytes, - unsigned numNewBytes); - void completeNewConfig(); - -private: - // redefined virtual functions: - virtual Boolean isMPEG4VideoStreamFramer() const; - -protected: - u_int8_t fProfileAndLevelIndication; - unsigned char* fConfigBytes; - unsigned fNumConfigBytes; - -private: - unsigned char* fNewConfigBytes; - unsigned fNumNewConfigBytes; - friend class MPEG4VideoStreamParser; // hack -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEGVideoStreamFramer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MPEGVideoStreamFramer.hh deleted file mode 100644 index 01791e76025..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MPEGVideoStreamFramer.hh +++ /dev/null @@ -1,84 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A filter that breaks up an MPEG video elementary stream into -// headers and frames -// C++ header - -#ifndef _MPEG_VIDEO_STREAM_FRAMER_HH -#define _MPEG_VIDEO_STREAM_FRAMER_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - -class TimeCode { -public: - TimeCode(); - virtual ~TimeCode(); - - int operator==(TimeCode const& arg2); - unsigned days, hours, minutes, seconds, pictures; -}; - -class MPEGVideoStreamFramer: public FramedFilter { -public: - Boolean& pictureEndMarker() { return fPictureEndMarker; } - // a hack for implementing the RTP 'M' bit - - void flushInput(); // called if there is a discontinuity (seeking) in the input - -protected: - MPEGVideoStreamFramer(UsageEnvironment& env, FramedSource* inputSource); - // we're an abstract base class - virtual ~MPEGVideoStreamFramer(); - - void computePresentationTime(unsigned numAdditionalPictures); - // sets "fPresentationTime" - void setTimeCode(unsigned hours, unsigned minutes, unsigned seconds, - unsigned pictures, unsigned picturesSinceLastGOP); - -private: // redefined virtual functions - virtual void doGetNextFrame(); - -private: - void reset(); - - static void continueReadProcessing(void* clientData, - unsigned char* ptr, unsigned size, - struct timeval presentationTime); - void continueReadProcessing(); - -protected: - double fFrameRate; // Note: For MPEG-4, this is really a 'tick rate' - unsigned fPictureCount; // hack used to implement doGetNextFrame() - Boolean fPictureEndMarker; - - // parsing state - class MPEGVideoStreamParser* fParser; - friend class MPEGVideoStreamParser; // hack - -private: - struct timeval fPresentationTimeBase; - TimeCode fCurGOPTimeCode, fPrevGOPTimeCode; - unsigned fPicturesAdjustment; - double fPictureTimeBase; - unsigned fTcSecsBase; - Boolean fHaveSeenFirstTimeCode; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/Media.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/Media.hh deleted file mode 100644 index abb9a7bad9d..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/Media.hh +++ /dev/null @@ -1,107 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Medium -// C++ header - -#ifndef _MEDIA_HH -#define _MEDIA_HH - -#ifndef _LIVEMEDIA_VERSION_HH -#include "liveMedia_version.hh" -#endif - -#ifndef _BOOLEAN_HH -#include "Boolean.hh" -#endif - -#ifndef _USAGE_ENVIRONMENT_HH -#include "UsageEnvironment.hh" -#endif - -// Lots of files end up needing the following, so just #include them here: -#ifndef _NET_COMMON_H -#include "NetCommon.h" -#endif -#include - -// The following makes the Borland compiler happy: -#ifdef __BORLANDC__ -#define _strnicmp strnicmp -#define fabsf(x) fabs(x) -#endif - -#define mediumNameMaxLen 30 - -class Medium { -public: - static Boolean lookupByName(UsageEnvironment& env, - char const* mediumName, - Medium*& resultMedium); - static void close(UsageEnvironment& env, char const* mediumName); - static void close(Medium* medium); // alternative close() method using ptrs - // (has no effect if medium == NULL) - - UsageEnvironment& envir() const {return fEnviron;} - - char const* name() const {return fMediumName;} - - // Test for specific types of media: - virtual Boolean isSource() const; - virtual Boolean isSink() const; - virtual Boolean isRTCPInstance() const; - virtual Boolean isRTSPClient() const; - virtual Boolean isRTSPServer() const; - virtual Boolean isMediaSession() const; - virtual Boolean isServerMediaSession() const; - virtual Boolean isDarwinInjector() const; - -protected: - Medium(UsageEnvironment& env); // abstract base class - virtual ~Medium(); // instances are deleted using close() only - - TaskToken& nextTask() { - return fNextTask; - } - -private: - friend class MediaLookupTable; - UsageEnvironment& fEnviron; - char fMediumName[mediumNameMaxLen]; - TaskToken fNextTask; -}; - -// The structure pointed to by the "liveMediaPriv" UsageEnvironment field: -class _Tables { -public: - static _Tables* getOurTables(UsageEnvironment& env); - // returns a pointer to an "ourTables" structure (creating it if necessary) - void reclaimIfPossible(); - // used to delete ourselves when we're no longer used - - void* mediaTable; - void* socketTable; - -protected: - _Tables(UsageEnvironment& env); - virtual ~_Tables(); - -private: - UsageEnvironment& fEnv; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSession.hh deleted file mode 100644 index 035e393965b..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSession.hh +++ /dev/null @@ -1,297 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A data structure that represents a session that consists of -// potentially multiple (audio and/or video) sub-sessions -// (This data structure is used for media *receivers* - i.e., clients. -// For media streamers, use "ServerMediaSession" instead.) -// C++ header - -#ifndef _MEDIA_SESSION_HH -#define _MEDIA_SESSION_HH - -#ifndef _RTCP_HH -#include "RTCP.hh" -#endif -#ifndef _PRIORITIZED_RTP_STREAM_SELELECTOR_HH -#include "PrioritizedRTPStreamSelector.hh" -#endif - -class MediaSubsession; // forward - -class MediaSession: public Medium { -public: - static MediaSession* createNew(UsageEnvironment& env, - char const* sdpDescription); - - static Boolean lookupByName(UsageEnvironment& env, char const* sourceName, - MediaSession*& resultSession); - - Boolean hasSubsessions() const { return fSubsessionsHead != NULL; } - float& playEndTime() { return fMaxPlayEndTime; } - char* connectionEndpointName() const { return fConnectionEndpointName; } - char const* CNAME() const { return fCNAME; } - struct in_addr const& sourceFilterAddr() const { return fSourceFilterAddr; } - float& scale() { return fScale; } - char* mediaSessionType() const { return fMediaSessionType; } - char* sessionName() const { return fSessionName; } - char* sessionDescription() const { return fSessionDescription; } - - Boolean initiateByMediaType(char const* mimeType, - MediaSubsession*& resultSubsession, - PrioritizedRTPStreamSelector*& resultMultiSource, - int& resultMultiSourceSessionId, - int useSpecialRTPoffset = -1); - // Initiates the first subsession with the specified MIME type (or - // perhaps multiple subsessions if MCT SLAP sessions are being used) - // Returns the resulting subsession, or 'multi source' (not both) - -#ifdef SUPPORT_REAL_RTSP - // Attributes specific to RealNetworks streams: - Boolean isRealNetworksRDT; - unsigned fRealFlags; - unsigned char* fRealTitle; unsigned fRealTitleSize; - unsigned char* fRealAuthor; unsigned fRealAuthorSize; - unsigned char* fRealCopyright; unsigned fRealCopyrightSize; - unsigned char* fRealAbstract; unsigned fRealAbstractSize; -#endif - -private: // redefined virtual functions - virtual Boolean isMediaSession() const; - -private: - MediaSession(UsageEnvironment& env); - // called only by createNew(); - virtual ~MediaSession(); - - Boolean initializeWithSDP(char const* sdpDescription); - Boolean parseSDPLine(char const* input, char const*& nextLine); - Boolean parseSDPLine_s(char const* sdpLine); - Boolean parseSDPLine_i(char const* sdpLine); - Boolean parseSDPLine_c(char const* sdpLine); - Boolean parseSDPAttribute_type(char const* sdpLine); - Boolean parseSDPAttribute_range(char const* sdpLine); - Boolean parseSDPAttribute_source_filter(char const* sdpLine); - - static char* lookupPayloadFormat(unsigned char rtpPayloadType, - unsigned& rtpTimestampFrequency, - unsigned& numChannels); - static unsigned guessRTPTimestampFrequency(char const* mediumName, - char const* codecName); - -private: - friend class MediaSubsessionIterator; - char* fCNAME; // used for RTCP - - // Linkage fields: - MediaSubsession* fSubsessionsHead; - MediaSubsession* fSubsessionsTail; - - // Fields set from a SDP description: - char* fConnectionEndpointName; - float fMaxPlayEndTime; - struct in_addr fSourceFilterAddr; // used for SSM - float fScale; // set from a RTSP "Scale:" header - char* fMediaSessionType; // holds a=type value - char* fSessionName; // holds s= value - char* fSessionDescription; // holds i= value -}; - - -class MediaSubsessionIterator { -public: - MediaSubsessionIterator(MediaSession& session); - virtual ~MediaSubsessionIterator(); - - MediaSubsession* next(); // NULL if none - void reset(); - -private: - MediaSession& fOurSession; - MediaSubsession* fNextPtr; -}; - - -class MediaSubsession { -public: - MediaSession& parentSession() { return fParent; } - MediaSession const& parentSession() const { return fParent; } - - unsigned short clientPortNum() const { return fClientPortNum; } - unsigned char rtpPayloadFormat() const { return fRTPPayloadFormat; } - char const* savedSDPLines() const { return fSavedSDPLines; } - char const* mediumName() const { return fMediumName; } - char const* codecName() const { return fCodecName; } - char const* protocolName() const { return fProtocolName; } - char const* controlPath() const { return fControlPath; } - Boolean isSSM() const { return fSourceFilterAddr.s_addr != 0; } - - int mctSLAPSessionId() const { return fMCT_SLAP_SessionId; } - unsigned mctSLAPStagger() const { return fMCT_SLAP_Stagger; } - unsigned short videoWidth() const { return fVideoWidth; } - unsigned short videoHeight() const { return fVideoHeight; } - unsigned videoFPS() const { return fVideoFPS; } - unsigned numChannels() const { return fNumChannels; } - float& scale() { return fScale; } - - RTPSource* rtpSource() { return fRTPSource; } - RTCPInstance* rtcpInstance() { return fRTCPInstance; } - unsigned rtpTimestampFrequency() const { return fRTPTimestampFrequency; } - FramedSource* readSource() { return fReadSource; } - // This is the source that client sinks read from. It is usually - // (but not necessarily) the same as "rtpSource()" - - float playEndTime() const; - - Boolean initiate(int useSpecialRTPoffset = -1); - // Creates a "RTPSource" for this subsession. (Has no effect if it's - // already been created.) Returns True iff this succeeds. - void deInitiate(); // Destroys any previously created RTPSource - Boolean setClientPortNum(unsigned short portNum); - // Sets the preferred client port number that any "RTPSource" for - // this subsession would use. (By default, the client port number - // is gotten from the original SDP description, or - if the SDP - // description does not specfy a client port number - an ephemeral - // (even) port number is chosen.) This routine should *not* be - // called after initiate(). - char*& connectionEndpointName() { return fConnectionEndpointName; } - char const* connectionEndpointName() const { - return fConnectionEndpointName; - } - - // Various parameters set in "a=fmtp:" SDP lines: - unsigned fmtp_auxiliarydatasizelength() const { return fAuxiliarydatasizelength; } - unsigned fmtp_constantduration() const { return fConstantduration; } - unsigned fmtp_constantsize() const { return fConstantsize; } - unsigned fmtp_crc() const { return fCRC; } - unsigned fmtp_ctsdeltalength() const { return fCtsdeltalength; } - unsigned fmtp_de_interleavebuffersize() const { return fDe_interleavebuffersize; } - unsigned fmtp_dtsdeltalength() const { return fDtsdeltalength; } - unsigned fmtp_indexdeltalength() const { return fIndexdeltalength; } - unsigned fmtp_indexlength() const { return fIndexlength; } - unsigned fmtp_interleaving() const { return fInterleaving; } - unsigned fmtp_maxdisplacement() const { return fMaxdisplacement; } - unsigned fmtp_objecttype() const { return fObjecttype; } - unsigned fmtp_octetalign() const { return fOctetalign; } - unsigned fmtp_profile_level_id() const { return fProfile_level_id; } - unsigned fmtp_robustsorting() const { return fRobustsorting; } - unsigned fmtp_sizelength() const { return fSizelength; } - unsigned fmtp_streamstateindication() const { return fStreamstateindication; } - unsigned fmtp_streamtype() const { return fStreamtype; } - Boolean fmtp_cpresent() const { return fCpresent; } - Boolean fmtp_randomaccessindication() const { return fRandomaccessindication; } - char const* fmtp_config() const { return fConfig; } - char const* fmtp_mode() const { return fMode; } - char const* fmtp_spropparametersets() const { return fSpropParameterSets; } - - unsigned connectionEndpointAddress() const; - // Converts "fConnectionEndpointName" to an address (or 0 if unknown) - void setDestinations(unsigned defaultDestAddress); - // Uses "fConnectionEndpointName" and "serverPortNum" to set - // the destination address and port of the RTP and RTCP objects. - // This is typically called by RTSP clients after doing "SETUP". - - // Public fields that external callers can use to keep state. - // (They are responsible for all storage management on these fields) - char const* sessionId; // used by RTSP - unsigned short serverPortNum; // in host byte order (used by RTSP) - unsigned char rtpChannelId, rtcpChannelId; // used by RTSP (for RTP/TCP) - MediaSink* sink; // callers can use this to keep track of who's playing us - void* miscPtr; // callers can use this for whatever they want - - // Parameters set from a RTSP "RTP-Info:" header: - struct { - unsigned trackId; - u_int16_t seqNum; - u_int32_t timestamp; - } rtpInfo; - -#ifdef SUPPORT_REAL_RTSP - // Attributes specific to RealNetworks streams: - unsigned fRealMaxBitRate, fRealAvgBitRate, fRealMaxPacketSize, fRealAvgPacketSize, fRealPreroll; - char* fRealStreamName; char* fRealMIMEType; - unsigned char* fRealOpaqueData; unsigned fRealOpaqueDataSize; - // A pointer into "fRealOpaqueData": - unsigned char* fRealTypeSpecificData; unsigned fRealTypeSpecificDataSize; - unsigned fRealRuleNumber; -#endif - -private: - friend class MediaSession; - friend class MediaSubsessionIterator; - MediaSubsession(MediaSession& parent); - virtual ~MediaSubsession(); - - UsageEnvironment& env() { return fParent.envir(); } - void setNext(MediaSubsession* next) { fNext = next; } - - Boolean parseSDPLine_c(char const* sdpLine); - Boolean parseSDPAttribute_rtpmap(char const* sdpLine); - Boolean parseSDPAttribute_control(char const* sdpLine); - Boolean parseSDPAttribute_range(char const* sdpLine); - Boolean parseSDPAttribute_fmtp(char const* sdpLine); - Boolean parseSDPAttribute_source_filter(char const* sdpLine); - Boolean parseSDPAttribute_x_mct_slap(char const* sdpLine); - Boolean parseSDPAttribute_x_dimensions(char const* sdpLine); - Boolean parseSDPAttribute_x_framerate(char const* sdpLine); - -private: - // Linkage fields: - MediaSession& fParent; - MediaSubsession* fNext; - - // Fields set from a SDP description: - char* fConnectionEndpointName; // may also be set by RTSP SETUP response - unsigned short fClientPortNum; // in host byte order - // This field is also set by initiate() - unsigned char fRTPPayloadFormat; - char* fSavedSDPLines; - char* fMediumName; - char* fCodecName; - char* fProtocolName; - unsigned fRTPTimestampFrequency; - char* fControlPath; - struct in_addr fSourceFilterAddr; // used for SSM - - // Parameters set by "a=fmtp:" SDP lines: - unsigned fAuxiliarydatasizelength, fConstantduration, fConstantsize; - unsigned fCRC, fCtsdeltalength, fDe_interleavebuffersize, fDtsdeltalength; - unsigned fIndexdeltalength, fIndexlength, fInterleaving; - unsigned fMaxdisplacement, fObjecttype; - unsigned fOctetalign, fProfile_level_id, fRobustsorting; - unsigned fSizelength, fStreamstateindication, fStreamtype; - Boolean fCpresent, fRandomaccessindication; - char *fConfig, *fMode, *fSpropParameterSets; - - float fPlayEndTime; - int fMCT_SLAP_SessionId; // 0 if not part of a MCT SLAP session - unsigned fMCT_SLAP_Stagger; // seconds (used only if the above is != 0) - unsigned short fVideoWidth, fVideoHeight; - // screen dimensions (set by an optional a=x-dimensions: , line) - unsigned fVideoFPS; - // frame rate (set by an optional a=x-framerate: line) - unsigned fNumChannels; - // optionally set by "a=rtpmap:" lines for audio sessions. Default: 1 - float fScale; // set from a RTSP "Scale:" header - - // Fields set by initiate(): - Groupsock* fRTPSocket; Groupsock* fRTCPSocket; // works even for unicast - RTPSource* fRTPSource; RTCPInstance* fRTCPInstance; - FramedSource* fReadSource; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSink.hh deleted file mode 100644 index 721716adaeb..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSink.hh +++ /dev/null @@ -1,129 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Media Sinks -// C++ header - -#ifndef _MEDIA_SINK_HH -#define _MEDIA_SINK_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif - -class MediaSink: public Medium { -public: - static Boolean lookupByName(UsageEnvironment& env, char const* sinkName, - MediaSink*& resultSink); - - typedef void (afterPlayingFunc)(void* clientData); - Boolean startPlaying(MediaSource& source, - afterPlayingFunc* afterFunc, - void* afterClientData); - virtual void stopPlaying(); - - // Test for specific types of sink: - virtual Boolean isRTPSink() const; - -protected: - MediaSink(UsageEnvironment& env); // abstract base class - virtual ~MediaSink(); - - virtual Boolean sourceIsCompatibleWithUs(MediaSource& source); - // called by startPlaying() - virtual Boolean continuePlaying() = 0; - // called by startPlaying() - - static void onSourceClosure(void* clientData); - // should be called (on ourselves) by continuePlaying() when it - // discovers that the source we're playing from has closed. - - FramedSource* fSource; - -private: - // redefined virtual functions: - virtual Boolean isSink() const; - -private: - // The following fields are used when we're being played: - afterPlayingFunc* fAfterFunc; - void* fAfterClientData; -}; - -// A data structure that a sink may use for an output packet: -class OutPacketBuffer { -public: - OutPacketBuffer(unsigned preferredPacketSize, unsigned maxPacketSize); - ~OutPacketBuffer(); - - static unsigned maxSize; - - unsigned char* curPtr() const {return &fBuf[fPacketStart + fCurOffset];} - unsigned totalBytesAvailable() const { - return fLimit - (fPacketStart + fCurOffset); - } - unsigned totalBufferSize() const { return fLimit; } - unsigned char* packet() const {return &fBuf[fPacketStart];} - unsigned curPacketSize() const {return fCurOffset;} - - void increment(unsigned numBytes) {fCurOffset += numBytes;} - - void enqueue(unsigned char const* from, unsigned numBytes); - void enqueueWord(unsigned word); - void insert(unsigned char const* from, unsigned numBytes, unsigned toPosition); - void insertWord(unsigned word, unsigned toPosition); - void extract(unsigned char* to, unsigned numBytes, unsigned fromPosition); - unsigned extractWord(unsigned fromPosition); - - void skipBytes(unsigned numBytes); - - Boolean isPreferredSize() const {return fCurOffset >= fPreferred;} - Boolean wouldOverflow(unsigned numBytes) const { - return (fCurOffset+numBytes) > fMax; - } - unsigned numOverflowBytes(unsigned numBytes) const { - return (fCurOffset+numBytes) - fMax; - } - Boolean isTooBigForAPacket(unsigned numBytes) const { - return numBytes > fMax; - } - - void setOverflowData(unsigned overflowDataOffset, - unsigned overflowDataSize, - struct timeval const& presentationTime, - unsigned durationInMicroseconds); - unsigned overflowDataSize() const {return fOverflowDataSize;} - struct timeval overflowPresentationTime() const {return fOverflowPresentationTime;} - unsigned overflowDurationInMicroseconds() const {return fOverflowDurationInMicroseconds;} - Boolean haveOverflowData() const {return fOverflowDataSize > 0;} - void useOverflowData(); - - void adjustPacketStart(unsigned numBytes); - void resetPacketStart(); - void resetOffset() { fCurOffset = 0; } - void resetOverflowData() { fOverflowDataOffset = fOverflowDataSize = 0; } - -private: - unsigned fPacketStart, fCurOffset, fPreferred, fMax, fLimit; - unsigned char* fBuf; - - unsigned fOverflowDataOffset, fOverflowDataSize; - struct timeval fOverflowPresentationTime; - unsigned fOverflowDurationInMicroseconds; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSource.hh deleted file mode 100644 index 483afc05e1b..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MediaSource.hh +++ /dev/null @@ -1,55 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Media Sources -// C++ header - -#ifndef _MEDIA_SOURCE_HH -#define _MEDIA_SOURCE_HH - -#ifndef _MEDIA_HH -#include "Media.hh" -#endif - -class MediaSource: public Medium { -public: - static Boolean lookupByName(UsageEnvironment& env, char const* sourceName, - MediaSource*& resultSource); - virtual void getAttributes() const; - // attributes are returned in "env's" 'result message' - - // The MIME type of this source: - virtual char const* MIMEtype() const; - - // Test for specific types of source: - virtual Boolean isFramedSource() const; - virtual Boolean isRTPSource() const; - virtual Boolean isMPEG1or2VideoStreamFramer() const; - virtual Boolean isMPEG4VideoStreamFramer() const; - virtual Boolean isJPEGVideoSource() const; - virtual Boolean isAMRAudioSource() const; - -protected: - MediaSource(UsageEnvironment& env); // abstract base class - virtual ~MediaSource(); - -private: - // redefined virtual functions: - virtual Boolean isSource() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MultiFramedRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MultiFramedRTPSink.hh deleted file mode 100644 index bd36457adc0..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MultiFramedRTPSink.hh +++ /dev/null @@ -1,120 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP sink for a common kind of payload format: Those which pack multiple, -// complete codec frames (as many as possible) into each RTP packet. -// C++ header - -#ifndef _MULTI_FRAMED_RTP_SINK_HH -#define _MULTI_FRAMED_RTP_SINK_HH - -#ifndef _RTP_SINK_HH -#include "RTPSink.hh" -#endif - -class MultiFramedRTPSink: public RTPSink { -public: - void setPacketSizes(unsigned preferredPacketSize, unsigned maxPacketSize); - -protected: - MultiFramedRTPSink(UsageEnvironment& env, - Groupsock* rtpgs, unsigned char rtpPayloadType, - unsigned rtpTimestampFrequency, - char const* rtpPayloadFormatName, - unsigned numChannels = 1); - // we're a virtual base class - - virtual ~MultiFramedRTPSink(); - - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - // perform any processing specific to the particular payload format - virtual Boolean allowFragmentationAfterStart() const; - // whether a frame can be fragmented if other frame(s) appear earlier - // in the packet (by default: False) - virtual Boolean allowOtherFramesAfterLastFragment() const; - // whether other frames can be packed into a packet following the - // final fragment of a previous, fragmented frame (by default: False) - virtual Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - // whether this frame can appear in position >1 in a pkt (default: True) - virtual unsigned specialHeaderSize() const; - // returns the size of any special header used (following the RTP header) - virtual unsigned frameSpecificHeaderSize() const; - // returns the size of any frame-specific header used (before each frame - // within the packet) - - // Functions that might be called by doSpecialFrameHandling(): - Boolean isFirstPacket() const { return fIsFirstPacket; } - Boolean isFirstFrameInPacket() const { return fNumFramesUsedSoFar == 0; } - Boolean curFragmentationOffset() const { return fCurFragmentationOffset; } - void setMarkerBit(); - void setTimestamp(struct timeval timestamp); - void setSpecialHeaderWord(unsigned word, /* 32 bits, in host order */ - unsigned wordPosition = 0); - void setSpecialHeaderBytes(unsigned char const* bytes, unsigned numBytes, - unsigned bytePosition = 0); - void setFrameSpecificHeaderWord(unsigned word, /* 32 bits, in host order */ - unsigned wordPosition = 0); - void setFrameSpecificHeaderBytes(unsigned char const* bytes, unsigned numBytes, - unsigned bytePosition = 0); - unsigned numFramesUsedSoFar() const { return fNumFramesUsedSoFar; } - -private: // redefined virtual functions: - virtual Boolean continuePlaying(); - virtual void stopPlaying(); - -private: - void buildAndSendPacket(Boolean isFirstPacket); - void packFrame(); - void sendPacketIfNecessary(); - static void sendNext(void* firstArg); - friend void sendNext(void*); - - static void afterGettingFrame(void* clientData, - unsigned numBytesRead, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned numBytesRead, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - Boolean isTooBigForAPacket(unsigned numBytes) const; - - static void ourHandleClosure(void* clientData); - -private: - OutPacketBuffer* fOutBuf; - - Boolean fNoFramesLeft; - unsigned fNumFramesUsedSoFar; - unsigned fCurFragmentationOffset; - Boolean fPreviousFrameEndedFragmentation; - - Boolean fIsFirstPacket; - struct timeval fNextSendTime; - unsigned fTimestampPosition; - unsigned fSpecialHeaderPosition; - unsigned fSpecialHeaderSize; // size in bytes of any special header used - unsigned fCurFrameSpecificHeaderPosition; - unsigned fCurFrameSpecificHeaderSize; // size in bytes of cur frame-specific header - unsigned fTotalFrameSpecificHeaderSizes; // size of all frame-specific hdrs in pkt -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/MultiFramedRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/MultiFramedRTPSource.hh deleted file mode 100644 index accf52da4ef..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/MultiFramedRTPSource.hh +++ /dev/null @@ -1,155 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP source for a common kind of payload format: Those which pack multiple, -// complete codec frames (as many as possible) into each RTP packet. -// C++ header - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#define _MULTI_FRAMED_RTP_SOURCE_HH - -#ifndef _RTP_SOURCE_HH -#include "RTPSource.hh" -#endif - -class BufferedPacket; // forward -class BufferedPacketFactory; // forward - -class MultiFramedRTPSource: public RTPSource { -protected: - MultiFramedRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - BufferedPacketFactory* packetFactory = NULL); - // virtual base class - virtual ~MultiFramedRTPSource(); - - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - // Subclasses redefine this to handle any special, payload format - // specific header that follows the RTP header. - - virtual Boolean packetIsUsableInJitterCalculation(unsigned char* packet, - unsigned packetSize); - // The default implementation returns True, but this can be redefined - -protected: - Boolean fCurrentPacketBeginsFrame; - Boolean fCurrentPacketCompletesFrame; - -protected: - // redefined virtual functions: - virtual void doStopGettingFrames(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - virtual void setPacketReorderingThresholdTime(unsigned uSeconds); - -private: - void reset(); - void doGetNextFrame1(); - - static void networkReadHandler(MultiFramedRTPSource* source, int /*mask*/); - friend void networkReadHandler(MultiFramedRTPSource*, int); - - Boolean fAreDoingNetworkReads; - Boolean fNeedDelivery; - Boolean fPacketLossInFragmentedFrame; - unsigned char* fSavedTo; - unsigned fSavedMaxSize; - - // A buffer to (optionally) hold incoming pkts that have been reorderered - class ReorderingPacketBuffer* fReorderingBuffer; -}; - - -// A 'packet data' class that's used to implement the above. -// Note that this can be subclassed - if desired - to redefine -// "nextEnclosedFrameSize()". - -class BufferedPacket { -public: - BufferedPacket(); - virtual ~BufferedPacket(); - - Boolean hasUsableData() const { return fTail > fHead; } - unsigned useCount() const { return fUseCount; } - - Boolean fillInData(RTPInterface& rtpInterface); - void assignMiscParams(unsigned short rtpSeqNo, unsigned rtpTimestamp, - struct timeval presentationTime, - Boolean hasBeenSyncedUsingRTCP, - Boolean rtpMarkerBit, struct timeval timeReceived); - void skip(unsigned numBytes); // used to skip over an initial header - void removePadding(unsigned numBytes); // used to remove trailing bytes - void appendData(unsigned char* newData, unsigned numBytes); - void use(unsigned char* to, unsigned toSize, - unsigned& bytesUsed, unsigned& bytesTruncated, - unsigned short& rtpSeqNo, unsigned& rtpTimestamp, - struct timeval& presentationTime, - Boolean& hasBeenSyncedUsingRTCP, Boolean& rtpMarkerBit); - - BufferedPacket*& nextPacket() { return fNextPacket; } - - unsigned short rtpSeqNo() const { return fRTPSeqNo; } - struct timeval const& timeReceived() const { return fTimeReceived; } - - unsigned char* data() const { return &fBuf[fHead]; } - unsigned dataSize() const { return fTail-fHead; } - Boolean rtpMarkerBit() const { return fRTPMarkerBit; } - -protected: - virtual void reset(); - virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, - unsigned dataSize); - // The above function has been deprecated. Instead, new subclasses should use: - virtual void getNextEnclosedFrameParameters(unsigned char*& framePtr, - unsigned dataSize, - unsigned& frameSize, - unsigned& frameDurationInMicroseconds); - - unsigned fPacketSize; - unsigned char* fBuf; - unsigned fHead; - unsigned fTail; - -private: - BufferedPacket* fNextPacket; // used to link together packets - - unsigned fUseCount; - unsigned short fRTPSeqNo; - unsigned fRTPTimestamp; - struct timeval fPresentationTime; // corresponding to "fRTPTimestamp" - Boolean fHasBeenSyncedUsingRTCP; - Boolean fRTPMarkerBit; - struct timeval fTimeReceived; -}; - -// A 'factory' class for creating "BufferedPacket" objects. -// If you want to subclass "BufferedPacket", then you'll also -// want to subclass this, to redefine createNewPacket() - -class BufferedPacketFactory { -public: - BufferedPacketFactory(); - virtual ~BufferedPacketFactory(); - - virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/OnDemandServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/OnDemandServerMediaSubsession.hh deleted file mode 100644 index e2bffe38d41..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/OnDemandServerMediaSubsession.hh +++ /dev/null @@ -1,88 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand. -// C++ header - -#ifndef _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH -#define _ON_DEMAND_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _SERVER_MEDIA_SESSION_HH -#include "ServerMediaSession.hh" -#endif -#ifndef _RTP_SINK_HH -#include "RTPSink.hh" -#endif - -class OnDemandServerMediaSubsession: public ServerMediaSubsession { -protected: // we're a virtual base class - OnDemandServerMediaSubsession(UsageEnvironment& env, Boolean reuseFirstSource); - virtual ~OnDemandServerMediaSubsession(); - -protected: // redefined virtual functions - virtual char const* sdpLines(); - virtual void getStreamParameters(unsigned clientSessionId, - netAddressBits clientAddress, - Port const& clientRTPPort, - Port const& clientRTCPPort, - int tcpSocketNum, - unsigned char rtpChannelId, - unsigned char rtcpChannelId, - netAddressBits& destinationAddress, - u_int8_t& destinationTTL, - Boolean& isMulticast, - Port& serverRTPPort, - Port& serverRTCPPort, - void*& streamToken); - virtual void startStream(unsigned clientSessionId, void* streamToken, - TaskFunc* rtcpRRHandler, - void* rtcpRRHandlerClientData, - unsigned short& rtpSeqNum, - unsigned& rtpTimestamp); - virtual void pauseStream(unsigned clientSessionId, void* streamToken); - virtual void seekStream(unsigned clientSessionId, void* streamToken, float seekNPT); - virtual void setStreamScale(unsigned clientSessionId, void* streamToken, float scale); - virtual void deleteStream(unsigned clientSessionId, void*& streamToken); - -protected: // new virtual functions, possibly redefined by subclasses - virtual char const* getAuxSDPLine(RTPSink* rtpSink, - FramedSource* inputSource); - virtual void seekStreamSource(FramedSource* inputSource, float seekNPT); - virtual void setStreamSourceScale(FramedSource* inputSource, float scale); - -protected: // new virtual functions, defined by all subclasses - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate) = 0; - // "estBitrate" is the stream's estimated bitrate, in kbps - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource) = 0; - -private: - void setSDPLinesFromRTPSink(RTPSink* rtpSink, FramedSource* inputSource); - // used to implement "sdpLines()" - -private: - Boolean fReuseFirstSource; - HashTable* fDestinationsHashTable; // indexed by client session id - void* fLastStreamToken; - char* fSDPLines; - char fCNAME[100]; // for RTCP -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/OutputFile.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/OutputFile.hh deleted file mode 100644 index 71b37d4e7b7..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/OutputFile.hh +++ /dev/null @@ -1,31 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Common routines for opening/closing named output files -// C++ header - -#ifndef _OUTPUT_FILE_HH -#define _OUTPUT_FILE_HH - -#include -#include - -FILE* OpenOutputFile(UsageEnvironment& env, char const* fileName); - -void CloseOutputFile(FILE* fid); - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/PassiveServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/PassiveServerMediaSubsession.hh deleted file mode 100644 index 1d5055dc939..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/PassiveServerMediaSubsession.hh +++ /dev/null @@ -1,73 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that represents an existing -// 'RTPSink', rather than one that creates new 'RTPSink's on demand. -// C++ header - -#ifndef _PASSIVE_SERVER_MEDIA_SUBSESSION_HH -#define _PASSIVE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _SERVER_MEDIA_SESSION_HH -#include "ServerMediaSession.hh" -#endif - -#ifndef _RTP_SINK_HH -#include "RTPSink.hh" -#endif -#ifndef _RTCP_HH -#include "RTCP.hh" -#endif - -class PassiveServerMediaSubsession: public ServerMediaSubsession { -public: - static PassiveServerMediaSubsession* createNew(RTPSink& rtpSink, - RTCPInstance* rtcpInstance = NULL); - -protected: - PassiveServerMediaSubsession(RTPSink& rtpSink, RTCPInstance* rtcpInstance); - // called only by createNew(); - virtual ~PassiveServerMediaSubsession(); - -protected: // redefined virtual functions - virtual char const* sdpLines(); - virtual void getStreamParameters(unsigned clientSessionId, - netAddressBits clientAddress, - Port const& clientRTPPort, - Port const& clientRTCPPort, - int tcpSocketNum, - unsigned char rtpChannelId, - unsigned char rtcpChannelId, - netAddressBits& destinationAddress, - u_int8_t& destinationTTL, - Boolean& isMulticast, - Port& serverRTPPort, - Port& serverRTCPPort, - void*& streamToken); - virtual void startStream(unsigned clientSessionId, void* streamToken, - TaskFunc* rtcpRRHandler, - void* rtcpRRHandlerClientData, - unsigned short& rtpSeqNum, - unsigned& rtpTimestamp); - -private: - RTPSink& fRTPSink; - RTCPInstance* fRTCPInstance; - char* fSDPLines; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/PrioritizedRTPStreamSelector.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/PrioritizedRTPStreamSelector.hh deleted file mode 100644 index 3377d1d2e6e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/PrioritizedRTPStreamSelector.hh +++ /dev/null @@ -1,76 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Select from multiple, prioritized RTP streams, based on RTP sequence -// number, producing a single output stream -// C++ header - -#ifndef _PRIORITIZED_RTP_STREAM_SELECTOR_HH -#define _PRIORITIZED_RTP_STREAM_SELECTOR_HH - -#ifndef _RTCP_HH -#include "RTCP.hh" -#endif - -class PrioritizedRTPStreamSelector: public FramedSource { -public: - static PrioritizedRTPStreamSelector* - createNew(UsageEnvironment& env, unsigned seqNumStagger); - // seqNumStagger is the maximum staggering of RTP sequence #s expected - - unsigned addInputRTPStream(RTPSource* inputStream, - RTCPInstance* inputStreamRTCP); - // the input streams are assumed to be added in priority order; - // highest priority first. Returns the priority (0 == highest) - void removeInputRTPStream(unsigned priority); // also closes stream - - static Boolean lookupByName(UsageEnvironment& env, - char const* sourceName, - PrioritizedRTPStreamSelector*& resultSource); - - friend class PrioritizedInputStreamDescriptor; - -private: - // Redefined virtual functions: - virtual Boolean isPrioritizedRTPStreamSelector() const; - void doGetNextFrame(); - -private: - PrioritizedRTPStreamSelector(UsageEnvironment& env, - unsigned seqNumStagger); - // called only by createNew() - virtual ~PrioritizedRTPStreamSelector(); - - void startReadingProcess(); - - void handleNewIncomingFrame(unsigned priority, unsigned short rtpSeqNo, - unsigned char* buffer, unsigned frameSize); - - Boolean deliverFrameToClient(unsigned& uSecondsToDefer); - static void completeDelivery(void* clientData); - -private: - unsigned fNextInputStreamPriority; - class PrioritizedInputStreamDescriptor* fInputStreams; - - class PacketWarehouse* fWarehouse; - - Boolean fAmCurrentlyReading; - Boolean fNeedAFrame; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/QCELPAudioRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/QCELPAudioRTPSource.hh deleted file mode 100644 index 9e6a732dce3..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/QCELPAudioRTPSource.hh +++ /dev/null @@ -1,39 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Qualcomm "PureVoice" (aka. "QCELP") Audio RTP Sources -// C++ header - -#ifndef _QCELP_AUDIO_RTP_SOURCE_HH -#define _QCELP_AUDIO_RTP_SOURCE_HH - -#ifndef _RTP_SOURCE_HH -#include "RTPSource.hh" -#endif - -class QCELPAudioRTPSource { -public: - static FramedSource* createNew(UsageEnvironment& env, - Groupsock* RTPgs, - RTPSource*& resultRTPSource, - unsigned char rtpPayloadFormat = 12, - unsigned rtpTimestampFrequency = 8000); - // This returns a source to read from, but "resultRTPSource" will - // point to RTP-related state. -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/QuickTimeFileSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/QuickTimeFileSink.hh deleted file mode 100644 index 912a35e00c9..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/QuickTimeFileSink.hh +++ /dev/null @@ -1,182 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A sink that generates a QuickTime file from a composite media session -// C++ header - -#ifndef _QUICKTIME_FILE_SINK_HH -#define _QUICKTIME_FILE_SINK_HH - -#ifndef _MEDIA_SESSION_HH -#include "MediaSession.hh" -#endif - -class QuickTimeFileSink: public Medium { -public: - static QuickTimeFileSink* createNew(UsageEnvironment& env, - MediaSession& inputSession, - char const* outputFileName, - unsigned bufferSize = 20000, - unsigned short movieWidth = 240, - unsigned short movieHeight = 180, - unsigned movieFPS = 15, - Boolean packetLossCompensate = False, - Boolean syncStreams = False, - Boolean generateHintTracks = False, - Boolean generateMP4Format = False); - - typedef void (afterPlayingFunc)(void* clientData); - Boolean startPlaying(afterPlayingFunc* afterFunc, - void* afterClientData); - - unsigned numActiveSubsessions() const { return fNumSubsessions; } - -private: - QuickTimeFileSink(UsageEnvironment& env, MediaSession& inputSession, - FILE* outFid, unsigned bufferSize, - unsigned short movieWidth, unsigned short movieHeight, - unsigned movieFPS, Boolean packetLossCompensate, - Boolean syncStreams, Boolean generateHintTracks, - Boolean generateMP4Format); - // called only by createNew() - virtual ~QuickTimeFileSink(); - - Boolean continuePlaying(); - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - static void onSourceClosure(void* clientData); - void onSourceClosure1(); - static void onRTCPBye(void* clientData); - void completeOutputFile(); - -private: - friend class SubsessionIOState; - MediaSession& fInputSession; - FILE* fOutFid; - unsigned fBufferSize; - Boolean fPacketLossCompensate; - Boolean fSyncStreams, fGenerateMP4Format; - struct timeval fNewestSyncTime, fFirstDataTime; - Boolean fAreCurrentlyBeingPlayed; - afterPlayingFunc* fAfterFunc; - void* fAfterClientData; - unsigned fAppleCreationTime; - unsigned fLargestRTPtimestampFrequency; - unsigned fNumSubsessions, fNumSyncedSubsessions; - struct timeval fStartTime; - Boolean fHaveCompletedOutputFile; - -private: - ///// Definitions specific to the QuickTime file format: - - unsigned addWord(unsigned word); - unsigned addHalfWord(unsigned short halfWord); - unsigned addByte(unsigned char byte) { - putc(byte, fOutFid); - return 1; - } - unsigned addZeroWords(unsigned numWords); - unsigned add4ByteString(char const* str); - unsigned addArbitraryString(char const* str, - Boolean oneByteLength = True); - unsigned addAtomHeader(char const* atomName); - // strlen(atomName) must be 4 - void setWord(unsigned filePosn, unsigned size); - - unsigned movieTimeScale() const {return fLargestRTPtimestampFrequency;} - - // Define member functions for outputting various types of atom: -#define _atom(name) unsigned addAtom_##name() - _atom(ftyp); // for MP4 format files - _atom(moov); - _atom(mvhd); - _atom(iods); // for MP4 format files - _atom(trak); - _atom(tkhd); - _atom(edts); - _atom(elst); - _atom(tref); - _atom(hint); - _atom(mdia); - _atom(mdhd); - _atom(hdlr); - _atom(minf); - _atom(smhd); - _atom(vmhd); - _atom(gmhd); - _atom(gmin); - unsigned addAtom_hdlr2(); - _atom(dinf); - _atom(dref); - _atom(alis); - _atom(stbl); - _atom(stsd); - unsigned addAtom_genericMedia(); - unsigned addAtom_soundMediaGeneral(); - _atom(ulaw); - _atom(alaw); - _atom(Qclp); - _atom(wave); - _atom(frma); - _atom(Fclp); - _atom(Hclp); - _atom(mp4a); -// _atom(wave); -// _atom(frma); - _atom(esds); - _atom(srcq); - _atom(h263); - _atom(mp4v); - _atom(rtp); - _atom(tims); - _atom(stts); - _atom(stsc); - _atom(stsz); - _atom(stco); - _atom(udta); - _atom(name); - _atom(hnti); - _atom(sdp); - _atom(hinf); - _atom(totl); - _atom(npck); - _atom(tpay); - _atom(trpy); - _atom(nump); - _atom(tpyl); - _atom(dmed); - _atom(dimm); - _atom(drep); - _atom(tmin); - _atom(tmax); - _atom(pmax); - _atom(dmax); - _atom(payt); - unsigned addAtom_dummy(); - -private: - unsigned short fMovieWidth, fMovieHeight; - unsigned fMovieFPS; - unsigned fMDATposition; - unsigned fMVHD_durationPosn; - unsigned fMaxTrackDurationM; // in movie time units - class SubsessionIOState* fCurrentIOState; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/QuickTimeGenericRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/QuickTimeGenericRTPSource.hh deleted file mode 100644 index 245aa6806dd..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/QuickTimeGenericRTPSource.hh +++ /dev/null @@ -1,68 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP Sources containing generic QuickTime stream data, as defined in -// -// C++ header - -#ifndef _QUICKTIME_GENERIC_RTP_SOURCE_HH -#define _QUICKTIME_GENERIC_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class QuickTimeGenericRTPSource: public MultiFramedRTPSource { -public: - static QuickTimeGenericRTPSource* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, unsigned rtpTimestampFrequency, - char const* mimeTypeString); - - // QuickTime-specific information, set from the QuickTime header - // in each packet. This, along with the data following the header, - // is used by receivers. - struct QTState { - char PCK; - unsigned timescale; - char* sdAtom; - unsigned sdAtomSize; - unsigned short width, height; - // later add other state as needed ##### - } qtState; - -protected: - virtual ~QuickTimeGenericRTPSource(); - -private: - QuickTimeGenericRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mimeTypeString); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; - -private: - char const* fMIMEtypeString; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/RTCP.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/RTCP.hh deleted file mode 100644 index 973a06cd681..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/RTCP.hh +++ /dev/null @@ -1,199 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTCP -// C++ header - -#ifndef _RTCP_HH -#define _RTCP_HH - -#ifndef _RTP_SINK_HH -#include "RTPSink.hh" -#endif -#ifndef _RTP_SOURCE_HH -#include "RTPSource.hh" -#endif - -class SDESItem { -public: - SDESItem(unsigned char tag, unsigned char const* value); - - unsigned char const* data() const {return fData;} - unsigned totalSize() const; - -private: - unsigned char fData[2 + 0xFF]; // first 2 bytes are tag and length -}; - -class RTCPMemberDatabase; // forward - -class RTCPInstance: public Medium { -public: - static RTCPInstance* createNew(UsageEnvironment& env, Groupsock* RTCPgs, - unsigned totSessionBW, /* in kbps */ - unsigned char const* cname, - RTPSink* sink, - RTPSource const* source, - Boolean isSSMSource = False); - - static Boolean lookupByName(UsageEnvironment& env, char const* instanceName, - RTCPInstance*& resultInstance); - - unsigned numMembers() const; - - void setByeHandler(TaskFunc* handlerTask, void* clientData, - Boolean handleActiveParticipantsOnly = True); - // Assigns a handler routine to be called if a "BYE" arrives. - // The handler is called once only; for subsequent "BYE"s, - // "setByeHandler()" would need to be called again. - // If "handleActiveParticipantsOnly" is True, then the handler is called - // only if the SSRC is for a known sender (if we have a "RTPSource"), - // or if the SSRC is for a known receiver (if we have a "RTPSink"). - // This prevents (for example) the handler for a multicast receiver being - // called if some other multicast receiver happens to exit. - // If "handleActiveParticipantsOnly" is False, then the handler is called - // for any incoming RTCP "BYE". - void setSRHandler(TaskFunc* handlerTask, void* clientData); - void setRRHandler(TaskFunc* handlerTask, void* clientData); - // Assigns a handler routine to be called if a "SR" or "RR" - // (respectively) arrives. Unlike "setByeHandler()", the handler will - // be called once for each incoming "SR" or "RR". (To turn off handling, - // call the function again with "handlerTask" (and "clientData") as NULL. - void setSpecificRRHandler(netAddressBits fromAddress, Port fromPort, - TaskFunc* handlerTask, void* clientData); - // Like "setRRHandler()", but applies only to "RR" packets that come from - // a specific source address and port. (Note that if both a specific - // and a general "RR" handler function is set, then both will be called.) - - Groupsock* RTCPgs() const { return fRTCPInterface.gs(); } - - void setStreamSocket(int sockNum, unsigned char streamChannelId); - void addStreamSocket(int sockNum, unsigned char streamChannelId); - void removeStreamSocket(int sockNum, unsigned char streamChannelId) { - fRTCPInterface.removeStreamSocket(sockNum, streamChannelId); - } - // hacks to allow sending RTP over TCP (RFC 2236, section 10.12) - - void setAuxilliaryReadHandler(AuxHandlerFunc* handlerFunc, - void* handlerClientData) { - fRTCPInterface.setAuxilliaryReadHandler(handlerFunc, - handlerClientData); - } - -protected: - RTCPInstance(UsageEnvironment& env, Groupsock* RTPgs, unsigned totSessionBW, - unsigned char const* cname, - RTPSink* sink, RTPSource const* source, - Boolean isSSMSource); - // called only by createNew() - virtual ~RTCPInstance(); - -private: - // redefined virtual functions: - virtual Boolean isRTCPInstance() const; - -private: - void addReport(); - void addSR(); - void addRR(); - void enqueueCommonReportPrefix(unsigned char packetType, u_int32_t SSRC, - unsigned numExtraWords = 0); - void enqueueCommonReportSuffix(); - void enqueueReportBlock(RTPReceptionStats* receptionStats); - void addSDES(); - void addBYE(); - - void sendBuiltPacket(); - - static void onExpire(RTCPInstance* instance); - void onExpire1(); - - static void incomingReportHandler(RTCPInstance* instance, int /*mask*/); - void incomingReportHandler1(); - void onReceive(int typeOfPacket, int totPacketSize, u_int32_t ssrc); - - void unsetSpecificRRHandler(netAddressBits fromAddress, Port fromPort); - -private: - unsigned char* fInBuf; - OutPacketBuffer* fOutBuf; - RTPInterface fRTCPInterface; - unsigned fTotSessionBW; - RTPSink* fSink; - RTPSource const* fSource; - Boolean fIsSSMSource; - - SDESItem fCNAME; - RTCPMemberDatabase* fKnownMembers; - unsigned fOutgoingReportCount; // used for SSRC member aging - - double fAveRTCPSize; - int fIsInitial; - double fPrevReportTime; - double fNextReportTime; - int fPrevNumMembers; - - int fLastSentSize; - int fLastReceivedSize; - u_int32_t fLastReceivedSSRC; - int fTypeOfEvent; - int fTypeOfPacket; - Boolean fHaveJustSentPacket; - unsigned fLastPacketSentSize; - - TaskFunc* fByeHandlerTask; - void* fByeHandlerClientData; - Boolean fByeHandleActiveParticipantsOnly; - TaskFunc* fSRHandlerTask; - void* fSRHandlerClientData; - TaskFunc* fRRHandlerTask; - void* fRRHandlerClientData; - AddressPortLookupTable* fSpecificRRHandlerTable; - -public: // because this stuff is used by an external "C" function - void schedule(double nextTime); - void reschedule(double nextTime); - void sendReport(); - void sendBYE(); - int typeOfEvent() {return fTypeOfEvent;} - int sentPacketSize() {return fLastSentSize;} - int packetType() {return fTypeOfPacket;} - int receivedPacketSize() {return fLastReceivedSize;} - int checkNewSSRC(); - void removeLastReceivedSSRC(); - void removeSSRC(u_int32_t ssrc, Boolean alsoRemoveStats); -}; - -// RTCP packet types: -const unsigned char RTCP_PT_SR = 200; -const unsigned char RTCP_PT_RR = 201; -const unsigned char RTCP_PT_SDES = 202; -const unsigned char RTCP_PT_BYE = 203; -const unsigned char RTCP_PT_APP = 204; - -// SDES tags: -const unsigned char RTCP_SDES_END = 0; -const unsigned char RTCP_SDES_CNAME = 1; -const unsigned char RTCP_SDES_NAME = 2; -const unsigned char RTCP_SDES_EMAIL = 3; -const unsigned char RTCP_SDES_PHONE = 4; -const unsigned char RTCP_SDES_LOC = 5; -const unsigned char RTCP_SDES_TOOL = 6; -const unsigned char RTCP_SDES_NOTE = 7; -const unsigned char RTCP_SDES_PRIV = 8; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/RTPInterface.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/RTPInterface.hh deleted file mode 100644 index 656ca5c720e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/RTPInterface.hh +++ /dev/null @@ -1,93 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// An abstraction of a network interface used for RTP (or RTCP). -// (This allows the RTP-over-TCP hack (RFC 2326, section 10.12) to -// be implemented transparently.) -// C++ header - -#ifndef _RTP_INTERFACE_HH -#define _RTP_INTERFACE_HH - -#ifndef _MEDIA_HH -#include -#endif -#ifndef _GROUPSOCK_HH -#include "Groupsock.hh" -#endif - -// Typedef for an optional auxilliary handler function, to be called -// when each new packet is read: -typedef void AuxHandlerFunc(void* clientData, unsigned char* packet, - unsigned packetSize); - -class tcpStreamRecord { -public: - tcpStreamRecord(int streamSocketNum, unsigned char streamChannelId, - tcpStreamRecord* next); - virtual ~tcpStreamRecord(); - -public: - tcpStreamRecord* fNext; - int fStreamSocketNum; - unsigned char fStreamChannelId; -}; - -class RTPInterface { -public: - RTPInterface(Medium* owner, Groupsock* gs); - virtual ~RTPInterface(); - - Groupsock* gs() const { return fGS; } - - void setStreamSocket(int sockNum, unsigned char streamChannelId); - void addStreamSocket(int sockNum, unsigned char streamChannelId); - void removeStreamSocket(int sockNum, unsigned char streamChannelId); - - void sendPacket(unsigned char* packet, unsigned packetSize); - void startNetworkReading(TaskScheduler::BackgroundHandlerProc* - handlerProc); - Boolean handleRead(unsigned char* buffer, unsigned bufferMaxSize, - unsigned& bytesRead, - struct sockaddr_in& fromAddress); - void stopNetworkReading(); - - UsageEnvironment& envir() const { return fOwner->envir(); } - - void setAuxilliaryReadHandler(AuxHandlerFunc* handlerFunc, - void* handlerClientData) { - fAuxReadHandlerFunc = handlerFunc; - fAuxReadHandlerClientData = handlerClientData; - } - -private: - friend class SocketDescriptor; - Medium* fOwner; - Groupsock* fGS; - tcpStreamRecord* fTCPStreams; // optional, for RTP-over-TCP streaming/receiving - - unsigned short fNextTCPReadSize; - // how much data (if any) is available to be read from the TCP stream - int fNextTCPReadStreamSocketNum; - unsigned char fNextTCPReadStreamChannelId; - TaskScheduler::BackgroundHandlerProc* fReadHandlerProc; // if any - - AuxHandlerFunc* fAuxReadHandlerFunc; - void* fAuxReadHandlerClientData; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/RTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/RTPSink.hh deleted file mode 100644 index 9eaf5b0c067..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/RTPSink.hh +++ /dev/null @@ -1,220 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP Sinks -// C++ header - -#ifndef _RTP_SINK_HH -#define _RTP_SINK_HH - -#ifndef _MEDIA_SINK_HH -#include "MediaSink.hh" -#endif -#ifndef _RTP_INTERFACE_HH -#include "RTPInterface.hh" -#endif - -class RTPTransmissionStatsDB; // forward - -class RTPSink: public MediaSink { -public: - static Boolean lookupByName(UsageEnvironment& env, char const* sinkName, - RTPSink*& resultSink); - - // used by RTCP: - u_int32_t SSRC() const {return fSSRC;} - // later need a means of changing the SSRC if there's a collision ##### - u_int32_t convertToRTPTimestamp(struct timeval tv); - unsigned packetCount() const {return fPacketCount;} - unsigned octetCount() const {return fOctetCount;} - - // used by RTSP servers: - Groupsock const& groupsockBeingUsed() const { return *(fRTPInterface.gs()); } - Groupsock& groupsockBeingUsed() { return *(fRTPInterface.gs()); } - - unsigned char rtpPayloadType() const { return fRTPPayloadType; } - unsigned rtpTimestampFrequency() const { return fTimestampFrequency; } - void setRTPTimestampFrequency(unsigned freq) { - fTimestampFrequency = freq; - } - char const* rtpPayloadFormatName() const {return fRTPPayloadFormatName;} - - unsigned numChannels() const { return fNumChannels; } - - virtual char const* sdpMediaType() const; // for use in SDP m= lines - char* rtpmapLine() const; // returns a string to be delete[]d - virtual char const* auxSDPLine(); - // optional SDP line (e.g. a=fmtp:...) - - u_int16_t currentSeqNo() const { return fSeqNo; } - u_int32_t currentTimestamp() const { return fCurrentTimestamp; } - - RTPTransmissionStatsDB& transmissionStatsDB() const { - return *fTransmissionStatsDB; - } - - void setStreamSocket(int sockNum, unsigned char streamChannelId) { - fRTPInterface.setStreamSocket(sockNum, streamChannelId); - } - void addStreamSocket(int sockNum, unsigned char streamChannelId) { - fRTPInterface.addStreamSocket(sockNum, streamChannelId); - } - void removeStreamSocket(int sockNum, unsigned char streamChannelId) { - fRTPInterface.removeStreamSocket(sockNum, streamChannelId); - } - // hacks to allow sending RTP over TCP (RFC 2236, section 10.12) - - void getTotalBitrate(unsigned& outNumBytes, double& outElapsedTime); - // returns the number of bytes sent since the last time that we - // were called, and resets the counter. - -protected: - RTPSink(UsageEnvironment& env, - Groupsock* rtpGS, unsigned char rtpPayloadType, - u_int32_t rtpTimestampFrequency, - char const* rtpPayloadFormatName, - unsigned numChannels); - // abstract base class - - virtual ~RTPSink(); - - RTPInterface fRTPInterface; - unsigned char fRTPPayloadType; - unsigned fPacketCount, fOctetCount, fTotalOctetCount /*incl RTP hdr*/; - struct timeval fTotalOctetCountStartTime; - u_int32_t fCurrentTimestamp; - u_int16_t fSeqNo; - -private: - // redefined virtual functions: - virtual Boolean isRTPSink() const; - -private: - u_int32_t timevalToTimestamp(struct timeval tv) const; - -private: - u_int32_t fSSRC, fTimestampBase; - unsigned fTimestampFrequency; - Boolean fHaveComputedFirstTimestamp; - char const* fRTPPayloadFormatName; - unsigned fNumChannels; - struct timeval fCreationTime; - - RTPTransmissionStatsDB* fTransmissionStatsDB; -}; - - -class RTPTransmissionStats; // forward - -class RTPTransmissionStatsDB { -public: - unsigned numReceivers() const { return fNumReceivers; } - - class Iterator { - public: - Iterator(RTPTransmissionStatsDB& receptionStatsDB); - virtual ~Iterator(); - - RTPTransmissionStats* next(); - // NULL if none - - private: - HashTable::Iterator* fIter; - }; - - // The following is called whenever a RTCP RR packet is received: - void noteIncomingRR(u_int32_t SSRC, struct sockaddr_in const& lastFromAddress, - unsigned lossStats, unsigned lastPacketNumReceived, - unsigned jitter, unsigned lastSRTime, unsigned diffSR_RRTime); - - // The following is called when a RTCP BYE packet is received: - void removeRecord(u_int32_t SSRC); - - RTPTransmissionStats* lookup(u_int32_t SSRC) const; - -private: // constructor and destructor, called only by RTPSink: - friend class RTPSink; - RTPTransmissionStatsDB(RTPSink& rtpSink); - virtual ~RTPTransmissionStatsDB(); - -private: - void add(u_int32_t SSRC, RTPTransmissionStats* stats); - -private: - friend class Iterator; - unsigned fNumReceivers; - RTPSink& fOurRTPSink; - HashTable* fTable; -}; - -class RTPTransmissionStats { -public: - u_int32_t SSRC() const {return fSSRC;} - struct sockaddr_in const& lastFromAddress() const {return fLastFromAddress;} - unsigned lastPacketNumReceived() const {return fLastPacketNumReceived;} - unsigned firstPacketNumReported() const {return fFirstPacketNumReported;} - unsigned totNumPacketsLost() const {return fTotNumPacketsLost;} - unsigned jitter() const {return fJitter;} - unsigned lastSRTime() const { return fLastSRTime; } - unsigned diffSR_RRTime() const { return fDiffSR_RRTime; } - unsigned roundTripDelay() const; - // The round-trip delay (in units of 1/65536 seconds) computed from - // the most recently-received RTCP RR packet. - struct timeval timeCreated() const {return fTimeCreated;} - struct timeval lastTimeReceived() const {return fTimeReceived;} - void getTotalOctetCount(u_int32_t& hi, u_int32_t& lo); - void getTotalPacketCount(u_int32_t& hi, u_int32_t& lo); - - // Information which requires at least two RRs to have been received: - Boolean oldValid() const {return fOldValid;} // Have two RRs been received? - unsigned packetsReceivedSinceLastRR() const; - u_int8_t packetLossRatio() const { return fPacketLossRatio; } - // as an 8-bit fixed-point number - int packetsLostBetweenRR() const; - -private: - // called only by RTPTransmissionStatsDB: - friend class RTPTransmissionStatsDB; - RTPTransmissionStats(RTPSink& rtpSink, u_int32_t SSRC); - virtual ~RTPTransmissionStats(); - - void noteIncomingRR(struct sockaddr_in const& lastFromAddress, - unsigned lossStats, unsigned lastPacketNumReceived, - unsigned jitter, - unsigned lastSRTime, unsigned diffSR_RRTime); - -private: - RTPSink& fOurRTPSink; - u_int32_t fSSRC; - struct sockaddr_in fLastFromAddress; - unsigned fLastPacketNumReceived; - u_int8_t fPacketLossRatio; - unsigned fTotNumPacketsLost; - unsigned fJitter; - unsigned fLastSRTime; - unsigned fDiffSR_RRTime; - struct timeval fTimeCreated, fTimeReceived; - Boolean fOldValid; - unsigned fOldLastPacketNumReceived; - unsigned fOldTotNumPacketsLost; - Boolean fFirstPacket; - unsigned fFirstPacketNumReported; - u_int32_t fLastOctetCount, fTotalOctetCount_hi, fTotalOctetCount_lo; - u_int32_t fLastPacketCount, fTotalPacketCount_hi, fTotalPacketCount_lo; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/RTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/RTPSource.hh deleted file mode 100644 index c221be0b558..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/RTPSource.hh +++ /dev/null @@ -1,251 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// RTP Sources -// C++ header - -#ifndef _RTP_SOURCE_HH -#define _RTP_SOURCE_HH - -#ifndef _FRAMED_SOURCE_HH -#include "FramedSource.hh" -#endif -#ifndef _RTP_INTERFACE_HH -#include "RTPInterface.hh" -#endif - -class RTPReceptionStatsDB; // forward - -class RTPSource: public FramedSource { -public: - static Boolean lookupByName(UsageEnvironment& env, char const* sourceName, - RTPSource*& resultSource); - - u_int16_t curPacketRTPSeqNum() const { return fCurPacketRTPSeqNum; } - u_int32_t curPacketRTPTimestamp() const { return fCurPacketRTPTimestamp; } - Boolean curPacketMarkerBit() const { return fCurPacketMarkerBit; } - - unsigned char rtpPayloadFormat() const { return fRTPPayloadFormat; } - - virtual Boolean hasBeenSynchronizedUsingRTCP(); - - Groupsock* RTPgs() const { return fRTPInterface.gs(); } - - virtual void setPacketReorderingThresholdTime(unsigned uSeconds) = 0; - - // used by RTCP: - u_int32_t SSRC() const { return fSSRC; } - // Note: This is *our* SSRC, not the SSRC in incoming RTP packets. - // later need a means of changing the SSRC if there's a collision ##### - - unsigned timestampFrequency() const {return fTimestampFrequency;} - - RTPReceptionStatsDB& receptionStatsDB() const { - return *fReceptionStatsDB; - } - - u_int32_t lastReceivedSSRC() const { return fLastReceivedSSRC; } - // Note: This is the SSRC in the most recently received RTP packet; not *our* SSRC - - void setStreamSocket(int sockNum, unsigned char streamChannelId) { - // hack to allow sending RTP over TCP (RFC 2236, section 10.12) - fRTPInterface.setStreamSocket(sockNum, streamChannelId); - } - - void setAuxilliaryReadHandler(AuxHandlerFunc* handlerFunc, - void* handlerClientData) { - fRTPInterface.setAuxilliaryReadHandler(handlerFunc, - handlerClientData); - } - -protected: - RTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, u_int32_t rtpTimestampFrequency); - // abstract base class - virtual ~RTPSource(); - -protected: - RTPInterface fRTPInterface; - u_int16_t fCurPacketRTPSeqNum; - u_int32_t fCurPacketRTPTimestamp; - Boolean fCurPacketMarkerBit; - Boolean fCurPacketHasBeenSynchronizedUsingRTCP; - u_int32_t fLastReceivedSSRC; - -private: - // redefined virtual functions: - virtual Boolean isRTPSource() const; - virtual void getAttributes() const; - -private: - unsigned char fRTPPayloadFormat; - unsigned fTimestampFrequency; - u_int32_t fSSRC; - - RTPReceptionStatsDB* fReceptionStatsDB; -}; - - -class RTPReceptionStats; // forward - -class RTPReceptionStatsDB { -public: - unsigned totNumPacketsReceived() const { return fTotNumPacketsReceived; } - unsigned numActiveSourcesSinceLastReset() const { - return fNumActiveSourcesSinceLastReset; - } - - void reset(); - // resets periodic stats (called each time they're used to - // generate a reception report) - - class Iterator { - public: - Iterator(RTPReceptionStatsDB& receptionStatsDB); - virtual ~Iterator(); - - RTPReceptionStats* next(Boolean includeInactiveSources = False); - // NULL if none - - private: - HashTable::Iterator* fIter; - }; - - // The following is called whenever a RTP packet is received: - void noteIncomingPacket(u_int32_t SSRC, u_int16_t seqNum, - u_int32_t rtpTimestamp, - unsigned timestampFrequency, - Boolean useForJitterCalculation, - struct timeval& resultPresentationTime, - Boolean& resultHasBeenSyncedUsingRTCP, - unsigned packetSize /* payload only */); - - // The following is called whenever a RTCP SR packet is received: - void noteIncomingSR(u_int32_t SSRC, - u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, - u_int32_t rtpTimestamp); - - // The following is called when a RTCP BYE packet is received: - void removeRecord(u_int32_t SSRC); - - RTPReceptionStats* lookup(u_int32_t SSRC) const; - -private: // constructor and destructor, called only by RTPSource: - friend class RTPSource; - RTPReceptionStatsDB(RTPSource& rtpSource); - virtual ~RTPReceptionStatsDB(); - -private: - void add(u_int32_t SSRC, RTPReceptionStats* stats); - -private: - friend class Iterator; - RTPSource& fOurRTPSource; - HashTable* fTable; - unsigned fNumActiveSourcesSinceLastReset; - unsigned fTotNumPacketsReceived; // for all SSRCs -}; - -class RTPReceptionStats { -public: - u_int32_t SSRC() const { return fSSRC; } - unsigned numPacketsReceivedSinceLastReset() const { - return fNumPacketsReceivedSinceLastReset; - } - unsigned totNumPacketsReceived() const { return fTotNumPacketsReceived; } - double totNumKBytesReceived() const; - - unsigned totNumPacketsExpected() const { - return fHighestExtSeqNumReceived - fBaseExtSeqNumReceived; - } - - unsigned baseExtSeqNumReceived() const { return fBaseExtSeqNumReceived; } - unsigned lastResetExtSeqNumReceived() const { - return fLastResetExtSeqNumReceived; - } - unsigned highestExtSeqNumReceived() const { - return fHighestExtSeqNumReceived; - } - - unsigned jitter() const; - - unsigned lastReceivedSR_NTPmsw() const { return fLastReceivedSR_NTPmsw; } - unsigned lastReceivedSR_NTPlsw() const { return fLastReceivedSR_NTPlsw; } - struct timeval const& lastReceivedSR_time() const { - return fLastReceivedSR_time; - } - - unsigned minInterPacketGapUS() const { return fMinInterPacketGapUS; } - unsigned maxInterPacketGapUS() const { return fMaxInterPacketGapUS; } - struct timeval const& totalInterPacketGaps() const { - return fTotalInterPacketGaps; - } - -private: - // called only by RTPReceptionStatsDB: - friend class RTPReceptionStatsDB; - RTPReceptionStats(RTPSource& rtpSource, u_int32_t SSRC, - u_int16_t initialSeqNum); - RTPReceptionStats(RTPSource& rtpSource, u_int32_t SSRC); - virtual ~RTPReceptionStats(); - - void noteIncomingPacket(u_int16_t seqNum, u_int32_t rtpTimestamp, - unsigned timestampFrequency, - Boolean useForJitterCalculation, - struct timeval& resultPresentationTime, - Boolean& resultHasBeenSyncedUsingRTCP, - unsigned packetSize /* payload only */); - void noteIncomingSR(u_int32_t ntpTimestampMSW, u_int32_t ntpTimestampLSW, - u_int32_t rtpTimestamp); - void init(u_int32_t SSRC); - void initSeqNum(u_int16_t initialSeqNum); - void reset(); - // resets periodic stats (called each time they're used to - // generate a reception report) - -private: - RTPSource& fOurRTPSource; - u_int32_t fSSRC; - unsigned fNumPacketsReceivedSinceLastReset; - unsigned fTotNumPacketsReceived; - u_int32_t fTotBytesReceived_hi, fTotBytesReceived_lo; - Boolean fHaveSeenInitialSequenceNumber; - unsigned fBaseExtSeqNumReceived; - unsigned fLastResetExtSeqNumReceived; - unsigned fHighestExtSeqNumReceived; - int fLastTransit; // used in the jitter calculation - u_int32_t fPreviousPacketRTPTimestamp; - double fJitter; - // The following are recorded whenever we receive a RTCP SR for this SSRC: - unsigned fLastReceivedSR_NTPmsw; // NTP timestamp (from SR), most-signif - unsigned fLastReceivedSR_NTPlsw; // NTP timestamp (from SR), least-signif - struct timeval fLastReceivedSR_time; - struct timeval fLastPacketReceptionTime; - unsigned fMinInterPacketGapUS, fMaxInterPacketGapUS; - struct timeval fTotalInterPacketGaps; - - // Used to convert from RTP timestamp to 'wall clock' time: - Boolean fHasBeenSynchronized; - u_int32_t fSyncTimestamp; - struct timeval fSyncTime; -}; - - -Boolean seqNumLT(u_int16_t s1, u_int16_t s2); - // a 'less-than' on 16-bit sequence numbers - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPClient.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPClient.hh deleted file mode 100644 index bce0e5e711c..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPClient.hh +++ /dev/null @@ -1,236 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A generic RTSP client -// C++ header - -#ifndef _RTSP_CLIENT_HH -#define _RTSP_CLIENT_HH - -#ifndef _MEDIA_SESSION_HH -#include "MediaSession.hh" -#endif -#ifndef _NET_ADDRESS_HH -#include "NetAddress.hh" -#endif -#ifndef _DIGEST_AUTHENTICATION_HH -#include "DigestAuthentication.hh" -#endif - -class RTSPClient: public Medium { -public: - static RTSPClient* createNew(UsageEnvironment& env, - int verbosityLevel = 0, - char const* applicationName = NULL, - portNumBits tunnelOverHTTPPortNum = 0); - // If "tunnelOverHTTPPortNum" is non-zero, we tunnel RTSP (and RTP) - // over a HTTP connection with the given port number, using the technique - // described in Apple's document - - int socketNum() const { return fInputSocketNum; } - - static Boolean lookupByName(UsageEnvironment& env, - char const* sourceName, - RTSPClient*& resultClient); - - char* describeURL(char const* url, Authenticator* authenticator = NULL, - Boolean allowKasennaProtocol = False); - // Issues a RTSP "DESCRIBE" command - // Returns the SDP description of a session, or NULL if none - // (This is dynamically allocated, and must later be freed - // by the caller - using "delete[]") - char* describeWithPassword(char const* url, - char const* username, char const* password); - // Uses "describeURL()" to do a "DESCRIBE" - first - // without using "password", then (if we get an Unauthorized - // response) with an authentication response computed from "password" - - Boolean announceSDPDescription(char const* url, - char const* sdpDescription, - Authenticator* authenticator = NULL); - // Issues a RTSP "ANNOUNCE" command - // Returns True iff this command succeeds - Boolean announceWithPassword(char const* url, char const* sdpDescription, - char const* username, char const* password); - // Uses "announceSDPDescription()" to do an "ANNOUNCE" - first - // without using "password", then (if we get an Unauthorized - // response) with an authentication response computed from "password" - - char* sendOptionsCmd(char const* url, - char* username = NULL, char* password = NULL, - Authenticator* authenticator = NULL); - // Issues a RTSP "OPTIONS" command - // Returns a string containing the list of options, or NULL - - Boolean setupMediaSubsession(MediaSubsession& subsession, - Boolean streamOutgoing = False, - Boolean streamUsingTCP = False, - Boolean forceMulticastOnUnspecified = False); - // Issues a RTSP "SETUP" command on "subsession". - // Returns True iff this command succeeds - // If "forceMulticastOnUnspecified" is True (and "streamUsingTCP" is False), - // then the client will request a multicast stream if the media address - // in the original SDP response was unspecified (i.e., 0.0.0.0). - // Note, however, that not all servers will support this. - - Boolean playMediaSession(MediaSession& session, - float start = 0.0f, float end = -1.0f, - float scale = 1.0f); - // Issues an aggregate RTSP "PLAY" command on "session". - // Returns True iff this command succeeds - // (Note: start=-1 means 'resume'; end=-1 means 'play to end') - Boolean playMediaSubsession(MediaSubsession& subsession, - float start = 0.0f, float end = -1.0f, - float scale = 1.0f, - Boolean hackForDSS = False); - // Issues a RTSP "PLAY" command on "subsession". - // Returns True iff this command succeeds - // (Note: start=-1 means 'resume'; end=-1 means 'play to end') - - Boolean pauseMediaSession(MediaSession& session); - // Issues an aggregate RTSP "PAUSE" command on "session". - // Returns True iff this command succeeds - Boolean pauseMediaSubsession(MediaSubsession& subsession); - // Issues a RTSP "PAUSE" command on "subsession". - // Returns True iff this command succeeds - - Boolean recordMediaSubsession(MediaSubsession& subsession); - // Issues a RTSP "RECORD" command on "subsession". - // Returns True iff this command succeeds - - Boolean setMediaSessionParameter(MediaSession& session, - char const* parameterName, - char const* parameterValue); - // Issues a RTSP "SET_PARAMETER" command on "subsession". - // Returns True iff this command succeeds - - Boolean getMediaSessionParameter(MediaSession& session, - char const* parameterName, - char*& parameterValue); - // Issues a RTSP "GET_PARAMETER" command on "subsession". - // Returns True iff this command succeeds - - Boolean teardownMediaSession(MediaSession& session); - // Issues an aggregate RTSP "TEARDOWN" command on "session". - // Returns True iff this command succeeds - Boolean teardownMediaSubsession(MediaSubsession& subsession); - // Issues a RTSP "TEARDOWN" command on "subsession". - // Returns True iff this command succeeds - - static Boolean parseRTSPURL(UsageEnvironment& env, char const* url, - NetAddress& address, portNumBits& portNum, - char const** urlSuffix = NULL); - // (ignores any "[:]@" in "url") - static Boolean parseRTSPURLUsernamePassword(char const* url, - char*& username, - char*& password); - - unsigned describeStatus() const { return fDescribeStatusCode; } - - void setUserAgentString(char const* userAgentStr); - // sets an alternative string to be used in RTSP "User-Agent:" headers - - unsigned sessionTimeoutParameter() const { return fSessionTimeoutParameter; } - -#ifdef SUPPORT_REAL_RTSP - Boolean usingRealNetworksChallengeResponse() const { return fRealChallengeStr != NULL; } -#endif - -protected: - virtual ~RTSPClient(); - -private: // redefined virtual functions - virtual Boolean isRTSPClient() const; - -private: - RTSPClient(UsageEnvironment& env, int verbosityLevel, - char const* applicationName, portNumBits tunnelOverHTTPPortNum); - // called only by createNew(); - - void reset(); - void resetTCPSockets(); - - Boolean openConnectionFromURL(char const* url, Authenticator* authenticator); - char* createAuthenticatorString(Authenticator const* authenticator, - char const* cmd, char const* url); - static void checkForAuthenticationFailure(unsigned responseCode, - char*& nextLineStart, - Authenticator* authenticator); - Boolean sendRequest(char const* requestString, char const* tag, - Boolean base64EncodeIfOverHTTP = True); - Boolean getResponse(char const* tag, - unsigned& bytesRead, unsigned& responseCode, - char*& firstLine, char*& nextLineStart, - Boolean checkFor200Response = True); - unsigned getResponse1(char*& responseBuffer, unsigned responseBufferSize); - Boolean parseResponseCode(char const* line, unsigned& responseCode); - Boolean parseTransportResponse(char const* line, - char*& serverAddressStr, - portNumBits& serverPortNum, - unsigned char& rtpChannelId, - unsigned char& rtcpChannelId); - Boolean parseRTPInfoHeader(char const* line, unsigned& trackId, - u_int16_t& seqNum, u_int32_t& timestamp); - Boolean parseScaleHeader(char const* line, float& scale); - Boolean parseGetParameterHeader(char const* line, - const char* param, - char*& value); - void constructSubsessionURL(MediaSubsession const& subsession, - char const*& prefix, - char const*& separator, - char const*& suffix); - Boolean setupHTTPTunneling(char const* urlSuffix, Authenticator* authenticator); - - // Support for handling requests sent back by a server: - static void incomingRequestHandler(void*, int /*mask*/); - void incomingRequestHandler1(); - void handleCmd_notSupported(char const* cseq); - -private: - int fVerbosityLevel; - portNumBits fTunnelOverHTTPPortNum; - char* fUserAgentHeaderStr; - unsigned fUserAgentHeaderStrSize; - int fInputSocketNum, fOutputSocketNum; - unsigned fServerAddress; - static unsigned fCSeq; // sequence number, used in consecutive requests - // Note: it's static, to ensure that it differs if more than one - // connection is made to the same server, using the same URL. - // Some servers (e.g., DSS) may have problems with this otherwise. - char* fBaseURL; - Authenticator fCurrentAuthenticator; - unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP - char* fLastSessionId; - unsigned fSessionTimeoutParameter; // optionally set in response "Session:" headers -#ifdef SUPPORT_REAL_RTSP - char* fRealChallengeStr; - char* fRealETagStr; -#endif - unsigned fDescribeStatusCode; - // 0: OK; 1: connection failed; 2: stream unavailable - char* fResponseBuffer; - unsigned fResponseBufferSize; - - // The following fields are used to implement the non-standard Kasenna protocol: - Boolean fServerIsKasenna; - char* fKasennaContentType; - - // The following is used to deal with Microsoft servers' non-standard use of RTSP: - Boolean fServerIsMicrosoft; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPCommon.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPCommon.hh deleted file mode 100644 index 46aa6376971..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPCommon.hh +++ /dev/null @@ -1,46 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Common routines used by both RTSP clients and servers -// C++ header - -#ifndef _RTSP_COMMON_HH -#define _RTSP_COMMON_HH - -#ifndef _BOOLEAN_HH -#include "Boolean.hh" -#endif - -#if defined(__WIN32__) || defined(_WIN32) || defined(_QNX4) -#define _strncasecmp _strnicmp -#define snprintf _snprintf -#else -#define _strncasecmp strncasecmp -#endif - -#define RTSP_PARAM_STRING_MAX 100 - -Boolean parseRTSPRequestString(char const *reqStr, unsigned reqStrSize, - char *resultCmdName, - unsigned resultCmdNameMaxSize, - char* resultURLPreSuffix, - unsigned resultURLPreSuffixMaxSize, - char* resultURLSuffix, - unsigned resultURLSuffixMaxSize, - char* resultCSeq, - unsigned resultCSeqMaxSize); -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPServer.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPServer.hh deleted file mode 100644 index 45be898d308..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/RTSPServer.hh +++ /dev/null @@ -1,182 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A RTSP server -// C++ header - -#ifndef _RTSP_SERVER_HH -#define _RTSP_SERVER_HH - -#ifndef _SERVER_MEDIA_SESSION_HH -#include "ServerMediaSession.hh" -#endif -#ifndef _NET_ADDRESS_HH -#include -#endif -#ifndef _DIGEST_AUTHENTICATION_HH -#include "DigestAuthentication.hh" -#endif - -// A data structure used for optional user/password authentication: - -class UserAuthenticationDatabase { -public: - UserAuthenticationDatabase(char const* realm = NULL, - Boolean passwordsAreMD5 = False); - // If "passwordsAreMD5" is True, then each password stored into, or removed from, - // the database is actually the value computed - // by md5(::) - virtual ~UserAuthenticationDatabase(); - - virtual void addUserRecord(char const* username, char const* password); - virtual void removeUserRecord(char const* username); - - virtual char const* lookupPassword(char const* username); - // returns NULL if the user name was not present - - char const* realm() { return fRealm; } - Boolean passwordsAreMD5() { return fPasswordsAreMD5; } - -protected: - HashTable* fTable; - char* fRealm; - Boolean fPasswordsAreMD5; -}; - -#define RTSP_BUFFER_SIZE 10000 // for incoming requests, and outgoing responses - -class RTSPServer: public Medium { -public: - static RTSPServer* createNew(UsageEnvironment& env, Port ourPort = 554, - UserAuthenticationDatabase* authDatabase = NULL, - unsigned reclamationTestSeconds = 45); - // If ourPort.num() == 0, we'll choose the port number - // Note: The caller is responsible for reclaiming "authDatabase" - // If "reclamationTestSeconds" > 0, then the "RTSPClientSession" state for - // each client will get reclaimed (and the corresponding RTP stream(s) - // torn down) if no RTSP commands - or RTCP "RR" packets - from the - // client are received in at least "reclamationTestSeconds" seconds. - - static Boolean lookupByName(UsageEnvironment& env, char const* name, - RTSPServer*& resultServer); - - void addServerMediaSession(ServerMediaSession* serverMediaSession); - ServerMediaSession* lookupServerMediaSession(char const* streamName); - void removeServerMediaSession(ServerMediaSession* serverMediaSession); - void removeServerMediaSession(char const* streamName); - - char* rtspURL(ServerMediaSession const* serverMediaSession) const; - // returns a "rtsp://" URL that could be used to access the - // specified session (which must already have been added to - // us using "addServerMediaSession()". - // This string is dynamically allocated; caller should delete[] - -protected: - RTSPServer(UsageEnvironment& env, - int ourSocket, Port ourPort, - UserAuthenticationDatabase* authDatabase, - unsigned reclamationTestSeconds); - // called only by createNew(); - virtual ~RTSPServer(); - - static int setUpOurSocket(UsageEnvironment& env, Port& ourPort); - -private: // redefined virtual functions - virtual Boolean isRTSPServer() const; - -private: - static void incomingConnectionHandler(void*, int /*mask*/); - void incomingConnectionHandler1(); - - // The state of each individual session handled by a RTSP server: - class RTSPClientSession { - public: - RTSPClientSession(RTSPServer& ourServer, unsigned sessionId, - int clientSocket, struct sockaddr_in clientAddr); - virtual ~RTSPClientSession(); - private: - UsageEnvironment& envir() { return fOurServer.envir(); } - void reclaimStreamStates(); - static void incomingRequestHandler(void*, int /*mask*/); - void incomingRequestHandler1(); - void handleCmd_bad(char const* cseq); - void handleCmd_notSupported(char const* cseq); - void handleCmd_notFound(char const* cseq); - void handleCmd_unsupportedTransport(char const* cseq); - void handleCmd_OPTIONS(char const* cseq); - void handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix, - char const* fullRequestStr); - void handleCmd_SETUP(char const* cseq, - char const* urlPreSuffix, char const* urlSuffix, - char const* fullRequestStr); - void handleCmd_withinSession(char const* cmdName, - char const* urlPreSuffix, char const* urlSuffix, - char const* cseq, char const* fullRequestStr); - void handleCmd_TEARDOWN(ServerMediaSubsession* subsession, - char const* cseq); - void handleCmd_PLAY(ServerMediaSubsession* subsession, - char const* cseq, char const* fullRequestStr); - void handleCmd_PAUSE(ServerMediaSubsession* subsession, - char const* cseq); - void handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession, - char const* cseq, char const* fullRequestStr); - Boolean authenticationOK(char const* cmdName, char const* cseq, - char const* fullRequestStr); - Boolean parseRequestString(char const *reqStr, unsigned reqStrSize, - char *resultCmdName, - unsigned resultCmdNameMaxSize, - char* resultURLPreSuffix, - unsigned resultURLPreSuffixMaxSize, - char* resultURLSuffix, - unsigned resultURLSuffixMaxSize, - char* resultCSeq, - unsigned resultCSeqMaxSize); - void noteLiveness(); - Boolean isMulticast() const { return fIsMulticast; } - static void noteClientLiveness(RTSPClientSession* clientSession); - static void livenessTimeoutTask(RTSPClientSession* clientSession); - - private: - RTSPServer& fOurServer; - unsigned fOurSessionId; - ServerMediaSession* fOurServerMediaSession; - int fClientSocket; - struct sockaddr_in fClientAddr; - TaskToken fLivenessCheckTask; - unsigned char fBuffer[RTSP_BUFFER_SIZE]; - unsigned char fResponseBuffer[RTSP_BUFFER_SIZE]; - Boolean fIsMulticast, fSessionIsActive, fStreamAfterSETUP; - Authenticator fCurrentAuthenticator; // used if access control is needed - unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP - unsigned fNumStreamStates; - struct streamState { - ServerMediaSubsession* subsession; - void* streamToken; - } * fStreamStates; - }; - -private: - friend class RTSPClientSession; - int fServerSocket; - Port fServerPort; - UserAuthenticationDatabase* fAuthDB; - unsigned fReclamationTestSeconds; - HashTable* fServerMediaSessions; - unsigned fSessionIdCounter; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/SIPClient.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/SIPClient.hh deleted file mode 100644 index 924997bec1e..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/SIPClient.hh +++ /dev/null @@ -1,148 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A generic SIP client -// C++ header - -#ifndef _SIP_CLIENT_HH -#define _SIP_CLIENT_HH - -#ifndef _MEDIA_SESSION_HH -#include "MediaSession.hh" -#endif -#ifndef _NET_ADDRESS_HH -#include "NetAddress.hh" -#endif -#ifndef _DIGEST_AUTHENTICATION_HH -#include "DigestAuthentication.hh" -#endif - -// Possible states in the "INVITE" transition diagram (RFC 3261, Figure 5) -enum inviteClientState { Calling, Proceeding, Completed, Terminated }; - -class SIPClient: public Medium { -public: - static SIPClient* createNew(UsageEnvironment& env, - unsigned char desiredAudioRTPPayloadFormat, - char const* mimeSubtype = NULL, - int verbosityLevel = 0, - char const* applicationName = NULL); - - void setProxyServer(unsigned proxyServerAddress, - portNumBits proxyServerPortNum); - - void setClientStartPortNum(portNumBits clientStartPortNum) { - fClientStartPortNum = clientStartPortNum; - } - - char* invite(char const* url, Authenticator* authenticator = NULL); - // Issues a SIP "INVITE" command - // Returns the session SDP description if this command succeeds - char* inviteWithPassword(char const* url, - char const* username, char const* password); - // Uses "invite()" to do an "INVITE" - first - // without using "password", then (if we get an Unauthorized - // response) with an authentication response computed from "password" - - Boolean sendACK(); // on current call - Boolean sendBYE(); // on current call - - static Boolean parseSIPURL(UsageEnvironment& env, char const* url, - NetAddress& address, portNumBits& portNum); - // (ignores any "[:]@" in "url") - static Boolean parseSIPURLUsernamePassword(char const* url, - char*& username, - char*& password); - - unsigned inviteStatus() const { return fInviteStatusCode; } - -protected: - virtual ~SIPClient(); - -private: - SIPClient(UsageEnvironment& env, - unsigned char desiredAudioRTPPayloadFormat, - char const* mimeSubtype, - int verbosityLevel, - char const* applicationName); - // called only by createNew(); - - void reset(); - - // Routines used to implement invite*(): - char* invite1(Authenticator* authenticator); - Boolean processURL(char const* url); - Boolean sendINVITE(); - static void inviteResponseHandler(void* clientData, int mask); - void doInviteStateMachine(unsigned responseCode); - void doInviteStateTerminated(unsigned responseCode); - TaskToken fTimerA, fTimerB, fTimerD; - static void timerAHandler(void* clientData); - static void timerBHandler(void* clientData); - static void timerDHandler(void* clientData); - unsigned const fT1; // in microseconds - unsigned fTimerALen; // in microseconds; initially fT1, then doubles - unsigned fTimerACount; - - // Routines used to implement all commands: - char* createAuthenticatorString(Authenticator const* authenticator, - char const* cmd, char const* url); - Boolean sendRequest(char const* requestString, unsigned requestLength); - unsigned getResponseCode(); - unsigned getResponse(char*& responseBuffer, unsigned responseBufferSize); - Boolean parseResponseCode(char const* line, unsigned& responseCode); - -private: - // Set for all calls: - unsigned char fDesiredAudioRTPPayloadFormat; - char* fMIMESubtype; - unsigned fMIMESubtypeSize; - int fVerbosityLevel; - unsigned fCSeq; // sequence number, used in consecutive requests - char const* fApplicationName; - unsigned fApplicationNameSize; - char const* fOurAddressStr; - unsigned fOurAddressStrSize; - portNumBits fOurPortNum; - Groupsock* fOurSocket; - char* fUserAgentHeaderStr; - unsigned fUserAgentHeaderStrSize; - - // Set for each call: - char const* fURL; - unsigned fURLSize; - struct in_addr fServerAddress; - portNumBits fServerPortNum; // in host order - portNumBits fClientStartPortNum; // in host order - unsigned fCallId, fFromTag; // set by us - char const* fToTagStr; // set by the responder - unsigned fToTagStrSize; - Authenticator fValidAuthenticator; - char const* fUserName; // 'user' name used in "From:" & "Contact:" lines - unsigned fUserNameSize; - - char* fInviteSDPDescription; - char* fInviteCmd; - unsigned fInviteCmdSize; - Authenticator* fWorkingAuthenticator; - inviteClientState fInviteClientState; - char fEventLoopStopFlag; - unsigned fInviteStatusCode; - // 0: OK; 1: connection failed; 2: stream unavailable -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/ServerMediaSession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/ServerMediaSession.hh deleted file mode 100644 index 1fb8e6ea833..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/ServerMediaSession.hh +++ /dev/null @@ -1,171 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A data structure that represents a session that consists of -// potentially multiple (audio and/or video) sub-sessions -// (This data structure is used for media *streamers* - i.e., servers. -// For media receivers, use "MediaSession" instead.) -// C++ header - -#ifndef _SERVER_MEDIA_SESSION_HH -#define _SERVER_MEDIA_SESSION_HH - -#ifndef _MEDIA_HH -#include "Media.hh" -#endif -#ifndef _GROUPEID_HH -#include "GroupEId.hh" -#endif - -class ServerMediaSubsession; // forward - -class ServerMediaSession: public Medium { -public: - static ServerMediaSession* createNew(UsageEnvironment& env, - char const* streamName = NULL, - char const* info = NULL, - char const* description = NULL, - Boolean isSSM = False, - char const* miscSDPLines = NULL); - - virtual ~ServerMediaSession(); - - static Boolean lookupByName(UsageEnvironment& env, - char const* mediumName, - ServerMediaSession*& resultSession); - - char* generateSDPDescription(); // based on the entire session - // Note: The caller is responsible for freeing the returned string - - char const* streamName() const { return fStreamName; } - - Boolean addSubsession(ServerMediaSubsession* subsession); - - void testScaleFactor(float& scale); // sets "scale" to the actual supported scale - float duration() const; - // a result == 0 means an unbounded session (the default) - // a result < 0 means: subsession durations differ; the result is -(the largest) - // a result > 0 means: this is the duration of a bounded session - - unsigned referenceCount() const { return fReferenceCount; } - void incrementReferenceCount() { ++fReferenceCount; } - void decrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; } - Boolean& deleteWhenUnreferenced() { return fDeleteWhenUnreferenced; } - -protected: - ServerMediaSession(UsageEnvironment& env, char const* streamName, - char const* info, char const* description, - Boolean isSSM, char const* miscSDPLines); - // called only by "createNew()" - -private: // redefined virtual functions - virtual Boolean isServerMediaSession() const; - -private: - Boolean fIsSSM; - - // Linkage fields: - friend class ServerMediaSubsessionIterator; - ServerMediaSubsession* fSubsessionsHead; - ServerMediaSubsession* fSubsessionsTail; - unsigned fSubsessionCounter; - - char* fStreamName; - char* fInfoSDPString; - char* fDescriptionSDPString; - char* fMiscSDPLines; - struct timeval fCreationTime; - unsigned fReferenceCount; - Boolean fDeleteWhenUnreferenced; -}; - - -class ServerMediaSubsessionIterator { -public: - ServerMediaSubsessionIterator(ServerMediaSession& session); - virtual ~ServerMediaSubsessionIterator(); - - ServerMediaSubsession* next(); // NULL if none - void reset(); - -private: - ServerMediaSession& fOurSession; - ServerMediaSubsession* fNextPtr; -}; - - -class ServerMediaSubsession: public Medium { -public: - virtual ~ServerMediaSubsession(); - - unsigned trackNumber() const { return fTrackNumber; } - char const* trackId(); - virtual char const* sdpLines() = 0; - virtual void getStreamParameters(unsigned clientSessionId, // in - netAddressBits clientAddress, // in - Port const& clientRTPPort, // in - Port const& clientRTCPPort, // in - int tcpSocketNum, // in (-1 means use UDP, not TCP) - unsigned char rtpChannelId, // in (used if TCP) - unsigned char rtcpChannelId, // in (used if TCP) - netAddressBits& destinationAddress, // in out - u_int8_t& destinationTTL, // in out - Boolean& isMulticast, // out - Port& serverRTPPort, // out - Port& serverRTCPPort, // out - void*& streamToken // out - ) = 0; - virtual void startStream(unsigned clientSessionId, void* streamToken, - TaskFunc* rtcpRRHandler, - void* rtcpRRHandlerClientData, - unsigned short& rtpSeqNum, - unsigned& rtpTimestamp) = 0; - virtual void pauseStream(unsigned clientSessionId, void* streamToken); - virtual void seekStream(unsigned clientSessionId, void* streamToken, float seekNPT); - virtual void setStreamScale(unsigned clientSessionId, void* streamToken, float scale); - virtual void deleteStream(unsigned clientSessionId, void*& streamToken); - - virtual void testScaleFactor(float& scale); // sets "scale" to the actual supported scale - virtual float duration() const; - // returns 0 for an unbounded session (the default) - // returns > 0 for a bounded session - - // The following may be called by (e.g.) SIP servers, for which the - // address and port number fields in SDP descriptions need to be non-zero: - void setServerAddressAndPortForSDP(netAddressBits addressBits, - portNumBits portBits); - -protected: // we're a virtual base class - ServerMediaSubsession(UsageEnvironment& env); - - char const* rangeSDPLine() const; - // returns a string to be delete[]d - - ServerMediaSession* fParentSession; - netAddressBits fServerAddressForSDP; - portNumBits fPortNumForSDP; - -private: - friend class ServerMediaSession; - friend class ServerMediaSubsessionIterator; - ServerMediaSubsession* fNext; - - unsigned fTrackNumber; // within an enclosing ServerMediaSession - char const* fTrackId; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/SimpleRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/SimpleRTPSink.hh deleted file mode 100644 index a6316f9caa0..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/SimpleRTPSink.hh +++ /dev/null @@ -1,73 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A simple RTP sink that packs frames into each outgoing -// packet, without any fragmentation or special headers. -// C++ header - -#ifndef _SIMPLE_RTP_SINK_HH -#define _SIMPLE_RTP_SINK_HH - -#ifndef _MULTI_FRAMED_RTP_SINK_HH -#include "MultiFramedRTPSink.hh" -#endif - -class SimpleRTPSink: public MultiFramedRTPSink { -public: - static SimpleRTPSink* - createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* sdpMediaTypeString, - char const* rtpPayloadFormatName, - unsigned numChannels = 1, - Boolean allowMultipleFramesPerPacket = True, - Boolean doNormalMBitRule = True); - // "doNormalMBitRule" means: If the medium is video, set the RTP "M" - // bit on each outgoing packet iff it contains the last (or only) - // fragment of a frame. (Otherwise, leave the "M" bit unset.) -protected: - SimpleRTPSink(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* sdpMediaTypeString, - char const* rtpPayloadFormatName, - unsigned numChannels, - Boolean allowMultipleFramesPerPacket, - Boolean doNormalMBitRule); - // called only by createNew() - - virtual ~SimpleRTPSink(); - -protected: // redefined virtual functions - virtual void doSpecialFrameHandling(unsigned fragmentationOffset, - unsigned char* frameStart, - unsigned numBytesInFrame, - struct timeval frameTimestamp, - unsigned numRemainingBytes); - virtual - Boolean frameCanAppearAfterPacketStart(unsigned char const* frameStart, - unsigned numBytesInFrame) const; - virtual char const* sdpMediaType() const; - -private: - char const* fSDPMediaTypeString; - Boolean fAllowMultipleFramesPerPacket; - Boolean fSetMBitOnLastFrames; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/SimpleRTPSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/SimpleRTPSource.hh deleted file mode 100644 index 806ccdb8d25..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/SimpleRTPSource.hh +++ /dev/null @@ -1,67 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A RTP source for a simple RTP payload format that -// - doesn't have any special headers following the RTP header -// (if necessary, the "offset" parameter can be used to specify a -// special header that we just skip over) -// - doesn't have any special framing apart from the packet data itself -// C++ header - -#ifndef _SIMPLE_RTP_SOURCE_HH -#define _SIMPLE_RTP_SOURCE_HH - -#ifndef _MULTI_FRAMED_RTP_SOURCE_HH -#include "MultiFramedRTPSource.hh" -#endif - -class SimpleRTPSource: public MultiFramedRTPSource { -public: - static SimpleRTPSource* createNew(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mimeTypeString, - unsigned offset = 0, - Boolean doNormalMBitRule = True); - // "doNormalMBitRule" means: If the medium is video, use the RTP "M" - // bit on each incoming packet to indicate the last (or only) fragment - // of a frame. (Otherwise, ignore the "M" bit.) - -protected: - virtual ~SimpleRTPSource(); - -private: - SimpleRTPSource(UsageEnvironment& env, Groupsock* RTPgs, - unsigned char rtpPayloadFormat, - unsigned rtpTimestampFrequency, - char const* mimeTypeString, unsigned offset, - Boolean doNormalMBitRule); - // called only by createNew() - -private: - // redefined virtual functions: - virtual Boolean processSpecialHeader(BufferedPacket* packet, - unsigned& resultSpecialHeaderSize); - virtual char const* MIMEtype() const; - -private: - char const* fMIMEtypeString; - unsigned fOffset; - Boolean fUseMBitForFrameEnd; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/VideoRTPSink.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/VideoRTPSink.hh deleted file mode 100644 index 62916b8e260..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/VideoRTPSink.hh +++ /dev/null @@ -1,41 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A generic RTP sink for video codecs (abstract base class) -// C++ header - -#ifndef _VIDEO_RTP_SINK_HH -#define _VIDEO_RTP_SINK_HH - -#ifndef _MULTI_FRAMED_RTP_SINK_HH -#include "MultiFramedRTPSink.hh" -#endif - -class VideoRTPSink: public MultiFramedRTPSink { -protected: - VideoRTPSink(UsageEnvironment& env, - Groupsock* rtpgs, unsigned char rtpPayloadType, - unsigned rtpTimestampFrequency, - char const* rtpPayloadFormatName); - // (we're an abstract base class) - virtual ~VideoRTPSink(); - -private: // redefined virtual functions: - virtual char const* sdpMediaType() const; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/WAVAudioFileServerMediaSubsession.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/WAVAudioFileServerMediaSubsession.hh deleted file mode 100644 index 8f70eecd834..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/WAVAudioFileServerMediaSubsession.hh +++ /dev/null @@ -1,65 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s -// on demand, from an WAV audio file. -// C++ header - -#ifndef _WAV_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH -#define _WAV_AUDIO_FILE_SERVER_MEDIA_SUBSESSION_HH - -#ifndef _FILE_SERVER_MEDIA_SUBSESSION_HH -#include "FileServerMediaSubsession.hh" -#endif - -class WAVAudioFileServerMediaSubsession: public FileServerMediaSubsession{ -public: - static WAVAudioFileServerMediaSubsession* - createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource, - Boolean convertToULaw = False); - // If "convertToULaw" is True, 16-bit audio streams are converted to - // 8-bit u-law audio prior to streaming. - -private: - WAVAudioFileServerMediaSubsession(UsageEnvironment& env, char const* fileName, - Boolean reuseFirstSource, Boolean convertToULaw); - // called only by createNew(); - virtual ~WAVAudioFileServerMediaSubsession(); - -private: // redefined virtual functions - virtual void seekStreamSource(FramedSource* inputSource, float seekNPT); - virtual void setStreamSourceScale(FramedSource* inputSource, float scale); - virtual FramedSource* createNewStreamSource(unsigned clientSessionId, - unsigned& estBitrate); - virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, - unsigned char rtpPayloadTypeIfDynamic, - FramedSource* inputSource); - virtual void testScaleFactor(float& scale); - virtual float duration() const; - -private: - Boolean fConvertToULaw; - - // The following parameters of the input stream are set after - // "createNewStreamSource" is called: - unsigned char fBitsPerSample; - unsigned fSamplingFrequency; - unsigned fNumChannels; - float fFileDuration; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/WAVAudioFileSource.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/WAVAudioFileSource.hh deleted file mode 100644 index de9a2b25da6..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/WAVAudioFileSource.hh +++ /dev/null @@ -1,61 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// A WAV audio file source -// NOTE: Samples are returned in little-endian order (the same order in which -// they were stored in the file). -// C++ header - -#ifndef _WAV_AUDIO_FILE_SOURCE_HH -#define _WAV_AUDIO_FILE_SOURCE_HH - -#ifndef _AUDIO_INPUT_DEVICE_HH -#include "AudioInputDevice.hh" -#endif - -class WAVAudioFileSource: public AudioInputDevice { -public: - static WAVAudioFileSource* createNew(UsageEnvironment& env, - char const* fileName); - - unsigned numPCMBytes() const; - void setScaleFactor(int scale); - void seekToPCMByte(unsigned byteNumber); - -protected: - WAVAudioFileSource(UsageEnvironment& env, FILE* fid); - // called only by createNew() - - virtual ~WAVAudioFileSource(); - -private: - // redefined virtual functions: - virtual void doGetNextFrame(); - virtual Boolean setInputPort(int portIndex); - virtual double getAverageLevel() const; - -private: - FILE* fFid; - double fPlayTimePerSample; // useconds - unsigned fPreferredFrameSize; - unsigned fLastPlayTime; // useconds - unsigned fWAVHeaderSize; - unsigned fFileSize; - int fScaleFactor; -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/liveMedia.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/liveMedia.hh deleted file mode 100644 index 533b2aba717..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/liveMedia.hh +++ /dev/null @@ -1,97 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Inclusion of header files representing the interface -// for the entire library -// -// Programs that use the library can include this header file, -// instead of each of the individual media header files - -#ifndef _LIVEMEDIA_HH -#define _LIVEMEDIA_HH - -#include "MPEG1or2AudioRTPSink.hh" -#include "MP3ADURTPSink.hh" -#include "MPEG1or2VideoRTPSink.hh" -#include "MPEG4ESVideoRTPSink.hh" -#include "AMRAudioFileSink.hh" -#include "BasicUDPSink.hh" -#include "MPEG1or2VideoHTTPSink.hh" -#include "GSMAudioRTPSink.hh" -#include "H263plusVideoRTPSink.hh" -#include "JPEGVideoRTPSink.hh" -#include "SimpleRTPSink.hh" -#include "uLawAudioFilter.hh" -#include "ByteStreamMultiFileSource.hh" -#include "BasicUDPSource.hh" -#include "SimpleRTPSource.hh" -#include "MPEG1or2AudioRTPSource.hh" -#include "MPEG4LATMAudioRTPSource.hh" -#include "MPEG4LATMAudioRTPSink.hh" -#include "MPEG4ESVideoRTPSource.hh" -#include "MPEG4GenericRTPSource.hh" -#include "MP3ADURTPSource.hh" -#include "QCELPAudioRTPSource.hh" -#include "AMRAudioRTPSource.hh" -#include "JPEGVideoRTPSource.hh" -#include "JPEGVideoSource.hh" -#include "MPEG1or2VideoRTPSource.hh" -#include "MPEG2TransportStreamFromPESSource.hh" -#include "MPEG2TransportStreamFromESSource.hh" -#include "MPEG2TransportStreamFramer.hh" -#include "ADTSAudioFileSource.hh" -#include "H261VideoRTPSource.hh" -#include "H263plusVideoRTPSource.hh" -#include "H264VideoRTPSource.hh" -#include "MP3HTTPSource.hh" -#include "MP3ADU.hh" -#include "MP3ADUinterleaving.hh" -#include "MP3Transcoder.hh" -#include "MPEG1or2DemuxedElementaryStream.hh" -#include "MPEG1or2AudioStreamFramer.hh" -#include "H263plusVideoStreamFramer.hh" -#include "AC3AudioStreamFramer.hh" -#include "AC3AudioRTPSource.hh" -#include "AC3AudioRTPSink.hh" -#include "MPEG4GenericRTPSink.hh" -#include "MPEG1or2VideoStreamDiscreteFramer.hh" -#include "MPEG4VideoStreamDiscreteFramer.hh" -#include "DeviceSource.hh" -#include "AudioInputDevice.hh" -#include "WAVAudioFileSource.hh" -#include "PrioritizedRTPStreamSelector.hh" -#include "RTSPServer.hh" -#include "RTSPClient.hh" -#include "SIPClient.hh" -#include "QuickTimeFileSink.hh" -#include "QuickTimeGenericRTPSource.hh" -#include "AVIFileSink.hh" -#include "PassiveServerMediaSubsession.hh" -#include "MPEG4VideoFileServerMediaSubsession.hh" -#include "WAVAudioFileServerMediaSubsession.hh" -#include "AMRAudioFileServerMediaSubsession.hh" -#include "AMRAudioFileSource.hh" -#include "AMRAudioRTPSink.hh" -#include "MP3AudioFileServerMediaSubsession.hh" -#include "MPEG1or2VideoFileServerMediaSubsession.hh" -#include "MPEG1or2FileServerDemux.hh" -#include "MPEG2TransportFileServerMediaSubsession.hh" -#include "H263plusVideoFileServerMediaSubsession.hh" -#include "ADTSAudioFileServerMediaSubsession.hh" -#include "DarwinInjector.hh" - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/liveMedia_version.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/liveMedia_version.hh deleted file mode 100644 index 19155164fd5..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/liveMedia_version.hh +++ /dev/null @@ -1,10 +0,0 @@ -// Version information for the "liveMedia" library -// Copyright (c) 1996-2006 Live Networks, Inc. All rights reserved. - -#ifndef _LIVEMEDIA_VERSION_HH -#define _LIVEMEDIA_VERSION_HH - -#define LIVEMEDIA_LIBRARY_VERSION_STRING "2006.05.17" -#define LIVEMEDIA_LIBRARY_VERSION_INT 1147824000 - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/include/uLawAudioFilter.hh b/mythtv/libs/libmythlivemedia/liveMedia/include/uLawAudioFilter.hh deleted file mode 100644 index 5ecbcc40832..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/include/uLawAudioFilter.hh +++ /dev/null @@ -1,181 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Filters for converting between raw PCM audio and uLaw -// C++ header - -#ifndef _ULAW_AUDIO_FILTER_HH -#define _ULAW_AUDIO_FILTER_HH - -#ifndef _FRAMED_FILTER_HH -#include "FramedFilter.hh" -#endif - -////////// 16-bit PCM (in various byte orderings) -> 8-bit u-Law ////////// - -class uLawFromPCMAudioSource: public FramedFilter { -public: - static uLawFromPCMAudioSource* - createNew(UsageEnvironment& env, FramedSource* inputSource, - int byteOrdering = 0); - // "byteOrdering" == 0 => host order (the default) - // "byteOrdering" == 1 => little-endian order - // "byteOrdering" == 2 => network (i.e., big-endian) order - -protected: - uLawFromPCMAudioSource(UsageEnvironment& env, FramedSource* inputSource, - int byteOrdering); - // called only by createNew() - virtual ~uLawFromPCMAudioSource(); - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - int fByteOrdering; - unsigned char* fInputBuffer; - unsigned fInputBufferSize; -}; - - -////////// u-Law -> 16-bit PCM (in host order) ////////// - -class PCMFromuLawAudioSource: public FramedFilter { -public: - static PCMFromuLawAudioSource* - createNew(UsageEnvironment& env, FramedSource* inputSource); - -protected: - PCMFromuLawAudioSource(UsageEnvironment& env, - FramedSource* inputSource); - // called only by createNew() - virtual ~PCMFromuLawAudioSource(); - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - -private: - unsigned char* fInputBuffer; - unsigned fInputBufferSize; -}; - - -////////// 16-bit values (in host order) -> 16-bit network order ////////// - -class NetworkFromHostOrder16: public FramedFilter { -public: - static NetworkFromHostOrder16* - createNew(UsageEnvironment& env, FramedSource* inputSource); - -protected: - NetworkFromHostOrder16(UsageEnvironment& env, FramedSource* inputSource); - // called only by createNew() - virtual ~NetworkFromHostOrder16(); - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); -}; - - -////////// 16-bit values (in network order) -> 16-bit host order ////////// - -class HostFromNetworkOrder16: public FramedFilter { -public: - static HostFromNetworkOrder16* - createNew(UsageEnvironment& env, FramedSource* inputSource); - -protected: - HostFromNetworkOrder16(UsageEnvironment& env, FramedSource* inputSource); - // called only by createNew() - virtual ~HostFromNetworkOrder16(); - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); -}; - - -////////// 16-bit values: little-endian <-> big-endian ////////// - -class EndianSwap16: public FramedFilter { -public: - static EndianSwap16* createNew(UsageEnvironment& env, FramedSource* inputSource); - -protected: - EndianSwap16(UsageEnvironment& env, FramedSource* inputSource); - // called only by createNew() - virtual ~EndianSwap16(); - -private: - // Redefined virtual functions: - virtual void doGetNextFrame(); - -private: - static void afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); - void afterGettingFrame1(unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds); -}; - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/our_md5.c b/mythtv/libs/libmythlivemedia/liveMedia/our_md5.c deleted file mode 100644 index 736d0bf9be2..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/our_md5.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm - */ - -/* - * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights - * reserved. - * - * License to copy and use this software is granted provided that it is - * identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" - * in all material mentioning or referencing this software or this function. - * - * License is also granted to make and use derivative works provided that such - * works are identified as "derived from the RSA Data Security, Inc. MD5 - * Message-Digest Algorithm" in all material mentioning or referencing the - * derived work. - * - * RSA Data Security, Inc. makes no representations concerning either the - * merchantability of this software or the suitability of this software for - * any particular purpose. It is provided "as is" without express or implied - * warranty of any kind. - * - * These notices must be retained in any copies of any part of this - * documentation and/or software. - */ - -#include "our_md5.h" -#include - -/* - * Constants for MD5Transform routine. - */ -#define S11 7 -#define S12 12 -#define S13 17 -#define S14 22 -#define S21 5 -#define S22 9 -#define S23 14 -#define S24 20 -#define S31 4 -#define S32 11 -#define S33 16 -#define S34 23 -#define S41 6 -#define S42 10 -#define S43 15 -#define S44 21 - -static unsigned char PADDING[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* - * F, G, H and I are basic MD5 functions. - */ -#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) -#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define I(x, y, z) ((y) ^ ((x) | (~z))) - -/* - * ROTATE_LEFT rotates x left n bits. - */ -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* - * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is - * separate from addition to prevent recomputation. - */ -#define FF(a, b, c, d, x, s, ac) { \ - (a) += F ((b), (c), (d)) + (x) + (UNSIGNED32)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define GG(a, b, c, d, x, s, ac) { \ - (a) += G ((b), (c), (d)) + (x) + (UNSIGNED32)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define HH(a, b, c, d, x, s, ac) { \ - (a) += H ((b), (c), (d)) + (x) + (UNSIGNED32)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } -#define II(a, b, c, d, x, s, ac) { \ - (a) += I ((b), (c), (d)) + (x) + (UNSIGNED32)(ac); \ - (a) = ROTATE_LEFT ((a), (s)); \ - (a) += (b); \ - } - -/* - * Encodes input (UNSIGNED32) into output (unsigned char). Assumes len is a - * multiple of 4. - */ -static void -Encode(unsigned char *output, UNSIGNED32 * input, unsigned int len) -{ - unsigned int i, j; - -#if 0 - assert((len % 4) == 0); -#endif - - for (i = 0, j = 0; j < len; i++, j += 4) { - output[j] = (unsigned char) (input[i] & 0xff); - output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff); - output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff); - output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff); - } -} - -/* - * Decodes input (unsigned char) into output (UNSIGNED32). Assumes len is a - * multiple of 4. - */ -static void -Decode(UNSIGNED32 * output, unsigned char const *input, unsigned int len) -{ - unsigned int i, j; - - for (i = 0, j = 0; j < len; i++, j += 4) - output[i] = ((UNSIGNED32) input[j]) | (((UNSIGNED32) input[j + 1]) << 8) | - (((UNSIGNED32) input[j + 2]) << 16) | (((UNSIGNED32) input[j + 3]) << 24); -} - -/* - * MD5 basic transformation. Transforms state based on block. - */ -static void -MD5Transform(UNSIGNED32 state[4], const unsigned char block[64]) -{ - UNSIGNED32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - - Decode(x, block, 64); - - /* Round 1 */ - FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ - FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ - FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ - FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ - FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ - FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ - FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ - FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ - FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ - FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ - FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ - FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ - FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ - FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ - FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ - FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ - - /* Round 2 */ - GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ - GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ - GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ - GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ - GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ - GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ - GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ - GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ - GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ - GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ - GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ - GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ - GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ - GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ - GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ - GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ - HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ - HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ - HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ - HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ - HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ - HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ - HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ - HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ - HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ - HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ - HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ - HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ - HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ - HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ - HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ - II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ - II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ - II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ - II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ - II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ - II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ - II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ - II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ - II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ - II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ - II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ - II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ - II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ - II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ - II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ - - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - - /* - * Zeroize sensitive information. - */ - memset((unsigned char *) x, 0, sizeof(x)); -} - -/** - * our_MD5Init: - * @context: MD5 context to be initialized. - * - * Initializes MD5 context for the start of message digest computation. - **/ -void -our_MD5Init(MD5_CTX * context) -{ - context->count[0] = context->count[1] = 0; - /* Load magic initialization constants. */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; - context->state[3] = 0x10325476; -} - -/** - * ourMD5Update: - * @context: MD5 context to be updated. - * @input: pointer to data to be fed into MD5 algorithm. - * @inputLen: size of @input data in bytes. - * - * MD5 block update operation. Continues an MD5 message-digest operation, - * processing another message block, and updating the context. - **/ - -void -ourMD5Update(MD5_CTX * context, const unsigned char *input, unsigned int inputLen) -{ - unsigned int i, index, partLen; - - /* Compute number of bytes mod 64 */ - index = (unsigned int) ((context->count[0] >> 3) & 0x3F); - - /* Update number of bits */ - if ((context->count[0] += ((UNSIGNED32) inputLen << 3)) < ((UNSIGNED32) inputLen << 3)) { - context->count[1]++; - } - context->count[1] += ((UNSIGNED32) inputLen >> 29); - - partLen = 64 - index; - - /* Transform as many times as possible. */ - if (inputLen >= partLen) { - memcpy((unsigned char *) & context->buffer[index], (unsigned char *) input, partLen); - MD5Transform(context->state, context->buffer); - - for (i = partLen; i + 63 < inputLen; i += 64) { - MD5Transform(context->state, &input[i]); - } - index = 0; - } else { - i = 0; - } - /* Buffer remaining input */ - if ((inputLen - i) != 0) { - memcpy((unsigned char *) & context->buffer[index], (unsigned char *) & input[i], inputLen - i); - } -} - -/** - * our_MD5Final: - * @digest: 16-byte buffer to write MD5 checksum. - * @context: MD5 context to be finalized. - * - * Ends an MD5 message-digest operation, writing the the message - * digest and zeroing the context. The context must be initialized - * with our_MD5Init() before being used for other MD5 checksum calculations. - **/ - -void -our_MD5Final(unsigned char digest[16], MD5_CTX * context) -{ - unsigned char bits[8]; - unsigned int index, padLen; - - /* Save number of bits */ - Encode(bits, context->count, 8); - - /* - * Pad out to 56 mod 64. - */ - index = (unsigned int) ((context->count[0] >> 3) & 0x3f); - padLen = (index < 56) ? (56 - index) : (120 - index); - ourMD5Update(context, PADDING, padLen); - - /* Append length (before padding) */ - ourMD5Update(context, bits, 8); - /* Store state in digest */ - Encode(digest, context->state, 16); - - /* - * Zeroize sensitive information. - */ - memset((unsigned char *) context, 0, sizeof(*context)); -} - diff --git a/mythtv/libs/libmythlivemedia/liveMedia/our_md5.h b/mythtv/libs/libmythlivemedia/liveMedia/our_md5.h deleted file mode 100644 index 32b11e5af0a..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/our_md5.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Because MD5 may not be implemented (at least, with the same - * interface) on all systems, we have our own copy here. - */ - -/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All -rights reserved. - -License to copy and use this software is granted provided that it -is identified as the "RSA Data Security, Inc. MD5 Message-Digest -Algorithm" in all material mentioning or referencing this software -or this function. - -License is also granted to make and use derivative works provided -that such works are identified as "derived from the RSA Data -Security, Inc. MD5 Message-Digest Algorithm" in all material -mentioning or referencing the derived work. - -RSA Data Security, Inc. makes no representations concerning either -the merchantability of this software or the suitability of this -software for any particular purpose. It is provided "as is" -without express or implied warranty of any kind. - -These notices must be retained in any copies of any part of this -documentation and/or software. - */ - -#ifndef _SYS_MD5_H_ -#define _SYS_MD5_H_ - -typedef unsigned UNSIGNED32; - -/* Definitions of _ANSI_ARGS and EXTERN that will work in either - C or C++ code: - */ -#undef _ANSI_ARGS_ -#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE) -# define _ANSI_ARGS_(x) x -#else -# define _ANSI_ARGS_(x) () -#endif -#ifdef __cplusplus -# define EXTERN extern "C" -#else -# define EXTERN extern -#endif - -/* MD5 context. */ -typedef struct MD5Context { - UNSIGNED32 state[4]; /* state (ABCD) */ - UNSIGNED32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -} MD5_CTX; - -EXTERN void our_MD5Init (MD5_CTX *); -EXTERN void ourMD5Update (MD5_CTX *, const unsigned char *, unsigned int); -EXTERN void our_MD5Pad (MD5_CTX *); -EXTERN void our_MD5Final (unsigned char [16], MD5_CTX *); -EXTERN char * our_MD5End(MD5_CTX *, char *); -EXTERN char * our_MD5File(const char *, char *); -EXTERN char * our_MD5Data(const unsigned char *, unsigned int, char *); -#endif /* _SYS_MD5_H_ */ diff --git a/mythtv/libs/libmythlivemedia/liveMedia/our_md5hl.c b/mythtv/libs/libmythlivemedia/liveMedia/our_md5hl.c deleted file mode 100644 index 1f24d128bd9..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/our_md5hl.c +++ /dev/null @@ -1,68 +0,0 @@ -#define LENGTH 16 -/* md5hl.c - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- - */ - -#include -#include -#include "our_md5.h" -#include "NetCommon.h" - -#ifndef BUFSIZ //pocket pc -#define BUFSIZ 255 -#endif - - -char * -our_MD5End(MD5_CTX *ctx, char *buf) -{ - int i; - unsigned char digest[LENGTH]; - static const char hex[]="0123456789abcdef"; - - if (!buf) - buf = (char*)malloc(2*LENGTH + 1); - if (!buf) - return 0; - our_MD5Final(digest, ctx); - for (i = 0; i < LENGTH; i++) { - buf[i+i] = hex[digest[i] >> 4]; - buf[i+i+1] = hex[digest[i] & 0x0f]; - } - buf[i+i] = '\0'; - return buf; -} - -char * -our_MD5File(const char *filename, char *buf) -{ - unsigned char buffer[BUFSIZ]; - MD5_CTX ctx; - int i; - FILE* f; - - our_MD5Init(&ctx); - f = fopen(filename, "r"); - if (f == NULL) return 0; - while ((i = fread(buffer,1,sizeof buffer,f)) > 0) { - ourMD5Update(&ctx,buffer,i); - } - fclose(f); - if (i < 0) return 0; - return our_MD5End(&ctx, buf); -} - -char * -our_MD5Data (const unsigned char *data, unsigned int len, char *buf) -{ - MD5_CTX ctx; - - our_MD5Init(&ctx); - ourMD5Update(&ctx,data,len); - return our_MD5End(&ctx, buf); -} diff --git a/mythtv/libs/libmythlivemedia/liveMedia/rtcp_from_spec.c b/mythtv/libs/libmythlivemedia/liveMedia/rtcp_from_spec.c deleted file mode 100644 index 6f9e45f46c4..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/rtcp_from_spec.c +++ /dev/null @@ -1,289 +0,0 @@ -/* RTCP code taken directly from the most recent RTP specification: - * draft-ietf-avt-rtp-new-11.txt - * Implementation - */ - -#include "rtcp_from_spec.h" - -/***** - -A.7 Computing the RTCP Transmission Interval - - The following functions implement the RTCP transmission and reception - rules described in Section 6.2. These rules are coded in several - functions: - - o rtcp_interval() computes the deterministic calculated - interval, measured in seconds. The parameters are defined in - Section 6.3. - - o OnExpire() is called when the RTCP transmission timer expires. - - o OnReceive() is called whenever an RTCP packet is received. - - Both OnExpire() and OnReceive() have event e as an argument. This is - the next scheduled event for that participant, either an RTCP report - or a BYE packet. It is assumed that the following functions are - available: - - o Schedule(time t, event e) schedules an event e to occur at - time t. When time t arrives, the function OnExpire is called - with e as an argument. - - o Reschedule(time t, event e) reschedules a previously scheduled - event e for time t. - - o SendRTCPReport(event e) sends an RTCP report. - - o SendBYEPacket(event e) sends a BYE packet. - - o TypeOfEvent(event e) returns EVENT_BYE if the event being - processed is for a BYE packet to be sent, else it returns - EVENT_REPORT. - - o PacketType(p) returns PACKET_RTCP_REPORT if packet p is an - RTCP report (not BYE), PACKET_BYE if its a BYE RTCP packet, - and PACKET_RTP if its a regular RTP data packet. - - o ReceivedPacketSize() and SentPacketSize() return the size of - the referenced packet in octets. - - o NewMember(p) returns a 1 if the participant who sent packet p - is not currently in the member list, 0 otherwise. Note this - function is not sufficient for a complete implementation - because each CSRC identifier in an RTP packet and each SSRC in - a BYE packet should be processed. - - o NewSender(p) returns a 1 if the participant who sent packet p - is not currently in the sender sublist of the member list, 0 - otherwise. - - o AddMember() and RemoveMember() to add and remove participants - from the member list. - - o AddSender() and RemoveSender() to add and remove participants - from the sender sublist of the member list. -*****/ - - - double rtcp_interval(int members, - int senders, - double rtcp_bw, - int we_sent, - double avg_rtcp_size, - int initial) - { - /* - * Minimum average time between RTCP packets from this site (in - * seconds). This time prevents the reports from `clumping' when - * sessions are small and the law of large numbers isn't helping - * to smooth out the traffic. It also keeps the report interval - * from becoming ridiculously small during transient outages like - * a network partition. - */ - double const RTCP_MIN_TIME = 5.; - /* - * Fraction of the RTCP bandwidth to be shared among active - * senders. (This fraction was chosen so that in a typical - * session with one or two active senders, the computed report - * time would be roughly equal to the minimum report time so that - * we don't unnecessarily slow down receiver reports.) The - * receiver fraction must be 1 - the sender fraction. - */ - double const RTCP_SENDER_BW_FRACTION = 0.25; - double const RTCP_RCVR_BW_FRACTION = (1-RTCP_SENDER_BW_FRACTION); - /* - * To compensate for "unconditional reconsideration" converging to a - * value below the intended average. - */ - double const COMPENSATION = 2.71828 - 1.5; - - double t; /* interval */ - double rtcp_min_time = RTCP_MIN_TIME; - int n; /* no. of members for computation */ - - /* - * Very first call at application start-up uses half the min - * delay for quicker notification while still allowing some time - * before reporting for randomization and to learn about other - * sources so the report interval will converge to the correct - * interval more quickly. - */ - if (initial) { - rtcp_min_time /= 2; - } - - /* - * If there were active senders, give them at least a minimum - * share of the RTCP bandwidth. Otherwise all participants share - * the RTCP bandwidth equally. - */ - n = members; - if (senders > 0 && senders < members * RTCP_SENDER_BW_FRACTION) { - if (we_sent) { - rtcp_bw *= RTCP_SENDER_BW_FRACTION; - n = senders; - } else { - rtcp_bw *= RTCP_RCVR_BW_FRACTION; - n -= senders; - } - } - - /* - * The effective number of sites times the average packet size is - * the total number of octets sent when each site sends a report. - * Dividing this by the effective bandwidth gives the time - * interval over which those packets must be sent in order to - * meet the bandwidth target, with a minimum enforced. In that - * time interval we send one report so this time is also our - * average time between reports. - */ - t = avg_rtcp_size * n / rtcp_bw; - if (t < rtcp_min_time) t = rtcp_min_time; - - /* - * To avoid traffic bursts from unintended synchronization with - * other sites, we then pick our actual next report interval as a - * random number uniformly distributed between 0.5*t and 1.5*t. - */ - t = t * (drand48() + 0.5); - t = t / COMPENSATION; - return t; - } - - void OnExpire(event e, - int members, - int senders, - double rtcp_bw, - int we_sent, - double *avg_rtcp_size, - int *initial, - time_tp tc, - time_tp *tp, - int *pmembers) - { - /* This function is responsible for deciding whether to send - * an RTCP report or BYE packet now, or to reschedule transmission. - * It is also responsible for updating the pmembers, initial, tp, - * and avg_rtcp_size state variables. This function should be called - * upon expiration of the event timer used by Schedule(). */ - - double t; /* Interval */ - double tn; /* Next transmit time */ - - /* In the case of a BYE, we use "unconditional reconsideration" to - * reschedule the transmission of the BYE if necessary */ - - if (TypeOfEvent(e) == EVENT_BYE) { - t = rtcp_interval(members, - senders, - rtcp_bw, - we_sent, - *avg_rtcp_size, - *initial); - tn = *tp + t; - if (tn <= tc) { - SendBYEPacket(e); - exit(1); - } else { - Schedule(tn, e); - } - - } else if (TypeOfEvent(e) == EVENT_REPORT) { - t = rtcp_interval(members, - senders, - rtcp_bw, - we_sent, - *avg_rtcp_size, - *initial); - tn = *tp + t; - - if (tn <= tc) { - SendRTCPReport(e); - *avg_rtcp_size = (1./16.)*SentPacketSize(e) + - (15./16.)*(*avg_rtcp_size); - *tp = tc; - - /* We must redraw the interval. Don't reuse the - one computed above, since its not actually - distributed the same, as we are conditioned - on it being small enough to cause a packet to - be sent */ - - t = rtcp_interval(members, - senders, - rtcp_bw, - we_sent, - *avg_rtcp_size, - *initial); - - Schedule(t+tc,e); - *initial = 0; - } else { - Schedule(tn, e); - } - *pmembers = members; - } - } - - - void OnReceive(packet p, - event e, - int *members, - int *pmembers, - int *senders, - double *avg_rtcp_size, - double *tp, - double tc, - double tn) - { - /* What we do depends on whether we have left the group, and - * are waiting to send a BYE (TypeOfEvent(e) == EVENT_BYE) or - * an RTCP report. p represents the packet that was just received. */ - - if (PacketType(p) == PACKET_RTCP_REPORT) { - if (NewMember(p) && (TypeOfEvent(e) == EVENT_REPORT)) { - AddMember(p); - *members += 1; - } - *avg_rtcp_size = (1./16.)*ReceivedPacketSize(p) + - (15./16.)*(*avg_rtcp_size); - } else if (PacketType(p) == PACKET_RTP) { - if (NewMember(p) && (TypeOfEvent(e) == EVENT_REPORT)) { - AddMember(p); - *members += 1; - } - if (NewSender(p) && (TypeOfEvent(e) == EVENT_REPORT)) { - AddSender(p); - *senders += 1; - } - } else if (PacketType(p) == PACKET_BYE) { - *avg_rtcp_size = (1./16.)*ReceivedPacketSize(p) + - (15./16.)*(*avg_rtcp_size); - - if (TypeOfEvent(e) == EVENT_REPORT) { - if (NewSender(p) == FALSE) { - RemoveSender(p); - *senders -= 1; - } - - if (NewMember(p) == FALSE) { - RemoveMember(p); - *members -= 1; - } - - if(*members < *pmembers) { - tn = tc + (((double) *members)/(*pmembers))*(tn - tc); - *tp = tc - (((double) *members)/(*pmembers))*(tc - *tp); - - /* Reschedule the next report for time tn */ - - Reschedule(tn, e); - *pmembers = *members; - } - - } else if (TypeOfEvent(e) == EVENT_BYE) { - *members += 1; - } - } - } diff --git a/mythtv/libs/libmythlivemedia/liveMedia/rtcp_from_spec.h b/mythtv/libs/libmythlivemedia/liveMedia/rtcp_from_spec.h deleted file mode 100644 index 64747b4bdfb..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/rtcp_from_spec.h +++ /dev/null @@ -1,78 +0,0 @@ -/* RTCP code taken directly from the most recent RTP specification: - * draft-ietf-avt-rtp-new-11.txt - * C header - */ - -#ifndef _RTCP_FROM_SPEC_H -#define _RTCP_FROM_SPEC_H - -#include - -/* Definitions of _ANSI_ARGS and EXTERN that will work in either - C or C++ code: - */ -#undef _ANSI_ARGS_ -#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE) -# define _ANSI_ARGS_(x) x -#else -# define _ANSI_ARGS_(x) () -#endif -#ifdef __cplusplus -# define EXTERN extern "C" -#else -# define EXTERN extern -#endif - -/* The code from the spec assumes a type "event"; make this a void*: */ -typedef void* event; - -#define EVENT_UNKNOWN 0 -#define EVENT_REPORT 1 -#define EVENT_BYE 2 - -/* The code from the spec assumes a type "time_tp"; make this a double: */ -typedef double time_tp; - -/* The code from the spec assumes a type "packet"; make this a void*: */ -typedef void* packet; - -#define PACKET_UNKNOWN_TYPE 0 -#define PACKET_RTP 1 -#define PACKET_RTCP_REPORT 2 -#define PACKET_BYE 3 - -/* The code from the spec calls drand48(), but we have drand30() instead */ -#define drand48 drand30 - -#ifndef FALSE -#define FALSE 0 -#endif -#ifndef TRUE -#define TRUE 1 -#endif - -/* EXPORTS: */ - -EXTERN void OnExpire _ANSI_ARGS_((event, int, int, double, int, double*, int*, time_tp, time_tp*, int*)); - -EXTERN void OnReceive _ANSI_ARGS_((packet, event, int*, int*, int*, double*, double*, double, double)); - -/* IMPORTS: */ - -EXTERN void Schedule _ANSI_ARGS_((double,event)); -EXTERN void Reschedule _ANSI_ARGS_((double,event)); -EXTERN void SendRTCPReport _ANSI_ARGS_((event)); -EXTERN void SendBYEPacket _ANSI_ARGS_((event)); -EXTERN int TypeOfEvent _ANSI_ARGS_((event)); -EXTERN int SentPacketSize _ANSI_ARGS_((event)); -EXTERN int PacketType _ANSI_ARGS_((packet)); -EXTERN int ReceivedPacketSize _ANSI_ARGS_((packet)); -EXTERN int NewMember _ANSI_ARGS_((packet)); -EXTERN int NewSender _ANSI_ARGS_((packet)); -EXTERN void AddMember _ANSI_ARGS_((packet)); -EXTERN void AddSender _ANSI_ARGS_((packet)); -EXTERN void RemoveMember _ANSI_ARGS_((packet)); -EXTERN void RemoveSender _ANSI_ARGS_((packet)); -EXTERN double drand30 _ANSI_ARGS_((void)); - -#endif diff --git a/mythtv/libs/libmythlivemedia/liveMedia/uLawAudioFilter.cpp b/mythtv/libs/libmythlivemedia/liveMedia/uLawAudioFilter.cpp deleted file mode 100644 index 110de232ee0..00000000000 --- a/mythtv/libs/libmythlivemedia/liveMedia/uLawAudioFilter.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/********** -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., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -**********/ -// "liveMedia" -// Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. -// Filters for converting between raw PCM audio and uLaw -// Implementation - -#include "uLawAudioFilter.hh" - -////////// 16-bit PCM (in various byte orders) -> 8-bit u-Law ////////// - -uLawFromPCMAudioSource* uLawFromPCMAudioSource -::createNew(UsageEnvironment& env, FramedSource* inputSource, int byteOrdering) { - // "byteOrdering" must be 0, 1, or 2: - if (byteOrdering < 0 || byteOrdering > 2) { - env.setResultMsg("uLawFromPCMAudioSource::createNew(): bad \"byteOrdering\" parameter"); - return NULL; - } - return new uLawFromPCMAudioSource(env, inputSource, byteOrdering); -} - -uLawFromPCMAudioSource -::uLawFromPCMAudioSource(UsageEnvironment& env, FramedSource* inputSource, - int byteOrdering) - : FramedFilter(env, inputSource), - fByteOrdering(byteOrdering), fInputBuffer(NULL), fInputBufferSize(0) { -} - -uLawFromPCMAudioSource::~uLawFromPCMAudioSource() { - delete[] fInputBuffer; -} - -void uLawFromPCMAudioSource::doGetNextFrame() { - // Figure out how many bytes of input data to ask for, and increase - // our input buffer if necessary: - unsigned bytesToRead = fMaxSize*2; // because we're converting 16 bits->8 - if (bytesToRead > fInputBufferSize) { - delete[] fInputBuffer; fInputBuffer = new unsigned char[bytesToRead]; - fInputBufferSize = bytesToRead; - } - - // Arrange to read samples into the input buffer: - fInputSource->getNextFrame(fInputBuffer, bytesToRead, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void uLawFromPCMAudioSource -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - uLawFromPCMAudioSource* source = (uLawFromPCMAudioSource*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -#define BIAS 0x84 // the add-in bias for 16 bit samples -#define CLIP 32635 - -static unsigned char uLawFrom16BitLinear(short sample) { - static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7}; - unsigned char sign = (sample >> 8) & 0x80; - if (sign != 0) sample = -sample; // get the magnitude - - if (sample > CLIP) sample = CLIP; // clip the magnitude - sample += BIAS; - - unsigned char exponent = exp_lut[(sample>>7) & 0xFF]; - unsigned char mantissa = (sample >> (exponent+3)) & 0x0F; - unsigned char result = ~(sign | (exponent << 4) | mantissa); - if (result == 0 ) result = 0x02; // CCITT trap - - return result; -} - -void uLawFromPCMAudioSource -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Translate raw 16-bit PCM samples (in the input buffer) - // into uLaw samples (in the output buffer). - unsigned numSamples = frameSize/2; - switch (fByteOrdering) { - case 0: { // host order - short* inputSample = (short*)fInputBuffer; - for (unsigned i = 0; i < numSamples; ++i) { - fTo[i] = uLawFrom16BitLinear(inputSample[i]); - } - break; - } - case 1: { // little-endian order - for (unsigned i = 0; i < numSamples; ++i) { - short const newValue = (fInputBuffer[2*i+1]<<8)|fInputBuffer[2*i]; - fTo[i] = uLawFrom16BitLinear(newValue); - } - break; - } - case 2: { // network (i.e., big-endian) order - for (unsigned i = 0; i < numSamples; ++i) { - short const newValue = (fInputBuffer[2*i]<<8)|fInputBuffer[2*i+i]; - fTo[i] = uLawFrom16BitLinear(newValue); - } - break; - } - } - - // Complete delivery to the client: - fFrameSize = numSamples; - fNumTruncatedBytes = numTruncatedBytes; - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - afterGetting(this); -} - - -////////// u-Law -> 16-bit PCM (in host order) ////////// - -PCMFromuLawAudioSource* PCMFromuLawAudioSource -::createNew(UsageEnvironment& env, FramedSource* inputSource) { - return new PCMFromuLawAudioSource(env, inputSource); -} - -PCMFromuLawAudioSource -::PCMFromuLawAudioSource(UsageEnvironment& env, - FramedSource* inputSource) - : FramedFilter(env, inputSource), - fInputBuffer(NULL), fInputBufferSize(0) { -} - -PCMFromuLawAudioSource::~PCMFromuLawAudioSource() { - delete[] fInputBuffer; -} - -void PCMFromuLawAudioSource::doGetNextFrame() { - // Figure out how many bytes of input data to ask for, and increase - // our input buffer if necessary: - unsigned bytesToRead = fMaxSize/2; // because we're converting 8 bits->16 - if (bytesToRead > fInputBufferSize) { - delete[] fInputBuffer; fInputBuffer = new unsigned char[bytesToRead]; - fInputBufferSize = bytesToRead; - } - - // Arrange to read samples into the input buffer: - fInputSource->getNextFrame(fInputBuffer, bytesToRead, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void PCMFromuLawAudioSource -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - PCMFromuLawAudioSource* source = (PCMFromuLawAudioSource*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -static short linear16FromuLaw(unsigned char uLawByte) { - static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764}; - uLawByte = ~uLawByte; - - Boolean sign = (uLawByte & 0x80) != 0; - unsigned char exponent = (uLawByte>>4) & 0x07; - unsigned char mantissa = uLawByte & 0x0F; - - short result = exp_lut[exponent] + (mantissa << (exponent+3)); - if (sign) result = -result; - return result; -} - -void PCMFromuLawAudioSource -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Translate uLaw samples (in the input buffer) - // into 16-bit PCM samples (in the output buffer), in host order. - unsigned numSamples = frameSize; - short* outputSample = (short*)fTo; - for (unsigned i = 0; i < numSamples; ++i) { - outputSample[i] = linear16FromuLaw(fInputBuffer[i]); - } - - // Complete delivery to the client: - fFrameSize = numSamples*2; - fNumTruncatedBytes = numTruncatedBytes; - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - afterGetting(this); -} - - -////////// 16-bit values (in host order) -> 16-bit network order ////////// - -NetworkFromHostOrder16* NetworkFromHostOrder16 -::createNew(UsageEnvironment& env, FramedSource* inputSource) { - return new NetworkFromHostOrder16(env, inputSource); -} - -NetworkFromHostOrder16 -::NetworkFromHostOrder16(UsageEnvironment& env, - FramedSource* inputSource) - : FramedFilter(env, inputSource) { -} - -NetworkFromHostOrder16::~NetworkFromHostOrder16() { -} - -void NetworkFromHostOrder16::doGetNextFrame() { - // Arrange to read data directly into the client's buffer: - fInputSource->getNextFrame(fTo, fMaxSize, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void NetworkFromHostOrder16 -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - NetworkFromHostOrder16* source = (NetworkFromHostOrder16*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -void NetworkFromHostOrder16 -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Translate the 16-bit values that we have just read from host - // to network order (in-place) - unsigned numValues = frameSize/2; - short* value = (short*)fTo; - for (unsigned i = 0; i < numValues; ++i) { - value[i] = htons(value[i]); - } - - // Complete delivery to the client: - fFrameSize = numValues*2; - fNumTruncatedBytes = numTruncatedBytes; - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - afterGetting(this); -} - - -////////// 16-bit values (in network order) -> 16-bit host order ////////// - -HostFromNetworkOrder16* HostFromNetworkOrder16 -::createNew(UsageEnvironment& env, FramedSource* inputSource) { - return new HostFromNetworkOrder16(env, inputSource); -} - -HostFromNetworkOrder16 -::HostFromNetworkOrder16(UsageEnvironment& env, - FramedSource* inputSource) - : FramedFilter(env, inputSource) { -} - -HostFromNetworkOrder16::~HostFromNetworkOrder16() { -} - -void HostFromNetworkOrder16::doGetNextFrame() { - // Arrange to read data directly into the client's buffer: - fInputSource->getNextFrame(fTo, fMaxSize, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void HostFromNetworkOrder16 -::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - HostFromNetworkOrder16* source = (HostFromNetworkOrder16*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -void HostFromNetworkOrder16 -::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Translate the 16-bit values that we have just read from network - // to host order (in-place): - unsigned numValues = frameSize/2; - short* value = (short*)fTo; - for (unsigned i = 0; i < numValues; ++i) { - value[i] = ntohs(value[i]); - } - - // Complete delivery to the client: - fFrameSize = numValues*2; - fNumTruncatedBytes = numTruncatedBytes; - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - afterGetting(this); -} - - -////////// 16-bit values: little-endian <-> big-endian ////////// - -EndianSwap16* -EndianSwap16::createNew(UsageEnvironment& env, FramedSource* inputSource) { - return new EndianSwap16(env, inputSource); -} - -EndianSwap16::EndianSwap16(UsageEnvironment& env, - FramedSource* inputSource) - : FramedFilter(env, inputSource) { -} - -EndianSwap16::~EndianSwap16() { -} - -void EndianSwap16::doGetNextFrame() { - // Arrange to read data directly into the client's buffer: - fInputSource->getNextFrame(fTo, fMaxSize, - afterGettingFrame, this, - FramedSource::handleClosure, this); -} - -void EndianSwap16::afterGettingFrame(void* clientData, unsigned frameSize, - unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - EndianSwap16* source = (EndianSwap16*)clientData; - source->afterGettingFrame1(frameSize, numTruncatedBytes, - presentationTime, durationInMicroseconds); -} - -void EndianSwap16::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, - struct timeval presentationTime, - unsigned durationInMicroseconds) { - // Swap the byte order of the 16-bit values that we have just read (in place): - unsigned numValues = frameSize/2; - short* value = (short*)fTo; - for (unsigned i = 0; i < numValues; ++i) { - short const orig = value[i]; - value[i] = ((orig&0xFF)<<8) | ((orig&0xFF00)>>8); - } - - // Complete delivery to the client: - fFrameSize = numValues*2; - fNumTruncatedBytes = numTruncatedBytes; - fPresentationTime = presentationTime; - fDurationInMicroseconds = durationInMicroseconds; - afterGetting(this); -} diff --git a/mythtv/libs/libmythtv/channelscan/channelscanner.cpp b/mythtv/libs/libmythtv/channelscan/channelscanner.cpp index deec82e78f6..fc5087f93a1 100644 --- a/mythtv/libs/libmythtv/channelscan/channelscanner.cpp +++ b/mythtv/libs/libmythtv/channelscan/channelscanner.cpp @@ -31,7 +31,6 @@ using namespace std; #include "analogsignalmonitor.h" -#include "iptvchannelfetcher.h" #include "dvbsignalmonitor.h" #include "scanwizardconfig.h" #include "channelscan_sm.h" @@ -46,7 +45,7 @@ using namespace std; #define LOC QString("ChScan: ") ChannelScanner::ChannelScanner() : - scanMonitor(NULL), channel(NULL), sigmonScanner(NULL), freeboxScanner(NULL), + scanMonitor(NULL), channel(NULL), sigmonScanner(NULL), freeToAirOnly(false), serviceRequirements(kRequireAV) { } @@ -76,15 +75,6 @@ void ChannelScanner::Teardown(void) channel = NULL; } -#ifdef USING_IPTV - if (freeboxScanner) - { - freeboxScanner->Stop(); - delete freeboxScanner; - freeboxScanner = NULL; - } -#endif // USING_IPTV - if (scanMonitor) { scanMonitor->deleteLater(); @@ -274,30 +264,6 @@ DTVConfParser::return_t ChannelScanner::ImportDVBUtils( return ret; } -bool ChannelScanner::ImportM3U( - uint cardid, const QString &inputname, uint sourceid) -{ - (void) cardid; - (void) inputname; - (void) sourceid; - bool ok = false; - -#ifdef USING_IPTV - // Create an IPTV scan object - freeboxScanner = new IPTVChannelFetcher( - cardid, inputname, sourceid, scanMonitor); - - MonitorProgress(false, false, false, false); - - ok = freeboxScanner->Scan(); -#endif // USING_IPTV - - if (!ok) - InformUser(QObject::tr("Error starting scan")); - - return ok; -} - void ChannelScanner::PreScanCommon( int scantype, uint cardid, diff --git a/mythtv/libs/libmythtv/channelscan/channelscanner.h b/mythtv/libs/libmythtv/channelscan/channelscanner.h index 98965368766..5c9e8f350eb 100644 --- a/mythtv/libs/libmythtv/channelscan/channelscanner.h +++ b/mythtv/libs/libmythtv/channelscan/channelscanner.h @@ -37,7 +37,6 @@ #include "channelscantypes.h" class ScanMonitor; -class IPTVChannelFetcher; class ChannelScanSM; class ChannelBase; @@ -74,9 +73,6 @@ class MTV_PUBLIC ChannelScanner virtual DTVConfParser::return_t ImportDVBUtils( uint sourceid, int cardtype, const QString &file); - virtual bool ImportM3U(uint cardid, const QString &inputname, - uint sourceid); - protected: virtual void Teardown(void); @@ -98,7 +94,6 @@ class MTV_PUBLIC ChannelScanner // Low level channel scanners ChannelScanSM *sigmonScanner; - IPTVChannelFetcher *freeboxScanner; /// imported channels DTVChannelList channels; diff --git a/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.cpp b/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.cpp deleted file mode 100644 index 57ba817b0dd..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.cpp +++ /dev/null @@ -1,423 +0,0 @@ -// -*- Mode: c++ -*- - -// Std C headers -#include -#include - -// Qt headers -#include -#include - -// MythTV headers -#include "mythcontext.h" -#include "httpcomms.h" -#include "cardutil.h" -#include "channelutil.h" -#include "iptvchannelfetcher.h" -#include "scanmonitor.h" -#include "mythlogging.h" - -#define LOC QString("IPTVChanFetch: ") - -static bool parse_chan_info(const QString &rawdata, - IPTVChannelInfo &info, - QString &channum, - uint &lineNum); - -static bool parse_extinf(const QString &data, - QString &channum, - QString &name); - -IPTVChannelFetcher::IPTVChannelFetcher( - uint cardid, const QString &inputname, uint sourceid, - ScanMonitor *monitor) : - _scan_monitor(monitor), - _cardid(cardid), _inputname(inputname), - _sourceid(sourceid), - _chan_cnt(1), _thread_running(false), - _stop_now(false), _thread(new MThread("IPTVChannelFetcher", this)), - _lock() -{ - _inputname.detach(); -} - -IPTVChannelFetcher::~IPTVChannelFetcher() -{ - Stop(); - delete _thread; - _thread = NULL; -} - -/** \fn IPTVChannelFetcher::Stop(void) - * \brief Stops the scanning thread running - */ -void IPTVChannelFetcher::Stop(void) -{ - _lock.lock(); - - while (_thread_running) - { - _stop_now = true; - _lock.unlock(); - _thread->wait(5); - _lock.lock(); - } - - _lock.unlock(); - - _thread->wait(); -} - -/** \fn IPTVChannelFetcher::Scan(void) - * \brief Scans the given frequency list, blocking call. - */ -bool IPTVChannelFetcher::Scan(void) -{ - _lock.lock(); - do { _lock.unlock(); Stop(); _lock.lock(); } while (_thread_running); - - // Should now have _lock and no thread should be running. - - _stop_now = false; - - _thread->start(); - - while (!_thread_running && !_stop_now) - usleep(5000); - - _lock.unlock(); - - return _thread_running; -} - -void IPTVChannelFetcher::run(void) -{ - _thread_running = true; - - // Step 1/4 : Get info from DB - QString url = CardUtil::GetVideoDevice(_cardid); - - if (_stop_now || url.isEmpty()) - { - _thread_running = false; - _stop_now = true; - return; - } - - LOG(VB_CHANNEL, LOG_INFO, QString("Playlist URL: %1").arg(url)); - - // Step 2/4 : Download - if (_scan_monitor) - { - _scan_monitor->ScanPercentComplete(5); - _scan_monitor->ScanAppendTextToLog(QObject::tr("Downloading Playlist")); - } - - QString playlist = DownloadPlaylist(url, true); - - if (_stop_now || playlist.isEmpty()) - { - _thread_running = false; - _stop_now = true; - return; - } - - // Step 3/4 : Process - if (_scan_monitor) - { - _scan_monitor->ScanPercentComplete(35); - _scan_monitor->ScanAppendTextToLog(QObject::tr("Processing Playlist")); - } - - const fbox_chan_map_t channels = ParsePlaylist(playlist, this); - - // Step 4/4 : Finish up - if (_scan_monitor) - _scan_monitor->ScanAppendTextToLog(QObject::tr("Adding Channels")); - SetTotalNumChannels(channels.size()); - fbox_chan_map_t::const_iterator it = channels.begin(); - for (uint i = 1; it != channels.end(); ++it, ++i) - { - QString channum = it.key(); - QString name = (*it).m_name; - QString xmltvid = (*it).m_xmltvid.isEmpty() ? "" : (*it).m_xmltvid; - QString msg = QObject::tr("Channel #%1 : %2").arg(channum).arg(name); - - int chanid = ChannelUtil::GetChanID(_sourceid, channum); - if (chanid <= 0) - { - if (_scan_monitor) - { - _scan_monitor->ScanAppendTextToLog( - QObject::tr("Adding %1").arg(msg)); - } - chanid = ChannelUtil::CreateChanID(_sourceid, channum); - ChannelUtil::CreateChannel( - 0, _sourceid, chanid, name, name, channum, - 0, 0, 0, false, false, false, QString::null, - QString::null, "Default", xmltvid); - } - else - { - if (_scan_monitor) - { - _scan_monitor->ScanAppendTextToLog( - QObject::tr("Updating %1").arg(msg)); - } - ChannelUtil::UpdateChannel( - 0, _sourceid, chanid, name, name, channum, - 0, 0, 0, false, false, false, QString::null, - QString::null, "Default", xmltvid); - } - - SetNumChannelsInserted(i); - } - - if (_scan_monitor) - { - _scan_monitor->ScanAppendTextToLog(QObject::tr("Done")); - _scan_monitor->ScanAppendTextToLog(""); - _scan_monitor->ScanPercentComplete(100); - _scan_monitor->ScanComplete(); - } - - _thread_running = false; - _stop_now = true; -} - -void IPTVChannelFetcher::SetNumChannelsParsed(uint val) -{ - uint minval = 35, range = 70 - minval; - uint pct = minval + (uint) truncf((((float)val) / _chan_cnt) * range); - if (_scan_monitor) - _scan_monitor->ScanPercentComplete(pct); -} - -void IPTVChannelFetcher::SetNumChannelsInserted(uint val) -{ - uint minval = 70, range = 100 - minval; - uint pct = minval + (uint) truncf((((float)val) / _chan_cnt) * range); - if (_scan_monitor) - _scan_monitor->ScanPercentComplete(pct); -} - -void IPTVChannelFetcher::SetMessage(const QString &status) -{ - if (_scan_monitor) - _scan_monitor->ScanAppendTextToLog(status); -} - -QString IPTVChannelFetcher::DownloadPlaylist(const QString &url, - bool inQtThread) -{ - if (url.left(4).toLower() == "file") - { - QString ret = ""; - QUrl qurl(url); - QFile file(qurl.toLocalFile()); - if (!file.open(QIODevice::ReadOnly)) - { - LOG(VB_GENERAL, LOG_ERR, LOC + QString("Opening '%1'") - .arg(qurl.toLocalFile()) + ENO); - return ret; - } - - QTextStream stream(&file); - while (!stream.atEnd()) - ret += stream.readLine() + "\n"; - - file.close(); - return ret; - } - - // Use Myth HttpComms for http URLs - QString redirected_url = url; - - QString tmp = HttpComms::getHttp( - redirected_url, - 10000 /* ms */, 3 /* retries */, - 3 /* redirects */, true /* allow gzip */, - NULL /* login */, inQtThread); - - if (redirected_url != url) - { - LOG(VB_CHANNEL, LOG_INFO, QString("Channel URL redirected to %1") - .arg(redirected_url)); - } - - return QString::fromUtf8(tmp.toAscii().constData()); -} - -static uint estimate_number_of_channels(const QString &rawdata) -{ - uint result = 0; - uint numLine = 1; - while (true) - { - QString url = rawdata.section("\n", numLine, numLine); - if (url.isEmpty()) - return result; - - ++numLine; - if (!url.startsWith("#")) // ignore comments - ++result; - } -} - -fbox_chan_map_t IPTVChannelFetcher::ParsePlaylist( - const QString &reallyrawdata, IPTVChannelFetcher *fetcher) -{ - fbox_chan_map_t chanmap; - - QString rawdata = reallyrawdata; - rawdata.replace("\r\n", "\n"); - - // Verify header is ok - QString header = rawdata.section("\n", 0, 0); - if (header != "#EXTM3U") - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("Invalid channel list header (%1)").arg(header)); - - if (fetcher) - { - fetcher->SetMessage( - QObject::tr("ERROR: M3U channel list is malformed")); - } - - return chanmap; - } - - // estimate number of channels - if (fetcher) - { - uint num_channels = estimate_number_of_channels(rawdata); - fetcher->SetTotalNumChannels(num_channels); - - LOG(VB_CHANNEL, LOG_INFO, - QString("Estimating there are %1 channels in playlist") - .arg(num_channels)); - } - - // Parse each channel - uint lineNum = 1; - for (uint i = 1; true; i++) - { - IPTVChannelInfo info; - QString channum = QString::null; - - if (!parse_chan_info(rawdata, info, channum, lineNum)) - break; - - QString msg = QObject::tr("Encountered malformed channel"); - if (!channum.isEmpty()) - { - chanmap[channum] = info; - - msg = QObject::tr("Parsing Channel #%1 : %2 : %3") - .arg(channum).arg(info.m_name).arg(info.m_url); - LOG(VB_CHANNEL, LOG_INFO, msg); - - msg = QString::null; // don't tell fetcher - } - - if (fetcher) - { - if (!msg.isEmpty()) - fetcher->SetMessage(msg); - fetcher->SetNumChannelsParsed(i); - } - } - - return chanmap; -} - -static bool parse_chan_info(const QString &rawdata, - IPTVChannelInfo &info, - QString &channum, - uint &lineNum) -{ - // #EXTINF:0,2 - France 2 <-- duration,channum - channame - // #EXTMYTHTV:xmltvid=C2.telepoche.com <-- optional line (myth specific) - // #... <-- ignored comments - // rtsp://maiptv.iptv.fr/iptvtv/201 <-- url - - QString name; - QString xmltvid; - while (true) - { - QString line = rawdata.section("\n", lineNum, lineNum); - if (line.isEmpty()) - return false; - - ++lineNum; - if (line.startsWith("#")) - { - if (line.startsWith("#EXTINF:")) - { - parse_extinf(line.mid(line.indexOf(':')+1), channum, name); - } - else if (line.startsWith("#EXTMYTHTV:")) - { - QString data = line.mid(line.indexOf(':')+1); - if (data.startsWith("xmltvid=")) - { - xmltvid = data.mid(data.indexOf('=')+1); - } - } - else - { - // Just ignore other comments - } - } - else - { - if (name.isEmpty()) - return false; - QString url = line; - info = IPTVChannelInfo(name, url, xmltvid); - return true; - } - } -} - -static bool parse_extinf(const QString &line1, - QString &channum, - QString &name) -{ - // data is supposed to contain the "0,2 - France 2" part - QString msg = LOC + - QString("Invalid header in channel list line \n\t\t\tEXTINF:%1") - .arg(line1); - - // Parse extension portion - int pos = line1.indexOf(","); - if (pos < 0) - { - LOG(VB_GENERAL, LOG_ERR, msg); - return false; - } - - // Parse iptv channel number - int oldpos = pos + 1; - pos = line1.indexOf(" ", pos + 1); - if (pos < 0) - { - LOG(VB_GENERAL, LOG_ERR, msg); - return false; - } - channum = line1.mid(oldpos, pos - oldpos); - - // Parse iptv channel name - pos = line1.indexOf("- ", pos + 1); - if (pos < 0) - { - LOG(VB_GENERAL, LOG_ERR, msg); - return false; - } - name = line1.mid(pos + 2, line1.length()); - - return true; -} - -/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.h b/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.h deleted file mode 100644 index d5b7a9fad7d..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvchannelfetcher.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _IPTVCHANNELFETCHER_H_ -#define _IPTVCHANNELFETCHER_H_ - -// Qt headers -#include -#include -#include - -// MythTV headers -#include "iptvchannelinfo.h" -#include "mthread.h" - -class ScanMonitor; -class IPTVChannelFetcher; - -class IPTVChannelFetcher : public QRunnable -{ - public: - IPTVChannelFetcher(uint cardid, const QString &inputname, uint sourceid, - ScanMonitor *monitor = NULL); - ~IPTVChannelFetcher(); - - bool Scan(void); - void Stop(void); - - static QString DownloadPlaylist(const QString &url, bool inQtThread); - static fbox_chan_map_t ParsePlaylist( - const QString &rawdata, IPTVChannelFetcher *fetcher = NULL); - - private: - void SetTotalNumChannels(uint val) { _chan_cnt = (val) ? val : 1; } - void SetNumChannelsParsed(uint); - void SetNumChannelsInserted(uint); - void SetMessage(const QString &status); - - protected: - virtual void run(void); // QRunnable - - private: - ScanMonitor *_scan_monitor; - uint _cardid; - QString _inputname; - uint _sourceid; - uint _chan_cnt; - bool _thread_running; - bool _stop_now; - MThread *_thread; - QMutex _lock; -}; - -#endif // _IPTVCHANNELFETCHER_H_ - -/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythtv/iptv/iptvchannelinfo.h b/mythtv/libs/libmythtv/iptv/iptvchannelinfo.h deleted file mode 100644 index fa2b5cd4d56..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvchannelinfo.h +++ /dev/null @@ -1,40 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVChannelInfo - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_CHANNELINFO_H_ -#define _IPTV_CHANNELINFO_H_ - -#include -#include - -class IPTVChannelInfo -{ - public: - IPTVChannelInfo() : - m_name(QString::null), - m_url(QString::null), - m_xmltvid(QString::null) {} - - IPTVChannelInfo(const QString &name, - const QString &url, - const QString &xmltvid) : - m_name(name), m_url(url), m_xmltvid(xmltvid) {} - - bool isValid(void) const - { - return !m_name.isEmpty() && !m_url.isEmpty(); - } - - public: - QString m_name; - QString m_url; - QString m_xmltvid; -}; - -typedef QMap fbox_chan_map_t; - -#endif // _IPTV_CHANNELINFO_H_ - -/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythtv/iptv/iptvfeeder.cpp b/mythtv/libs/libmythtv/iptv/iptvfeeder.cpp deleted file mode 100644 index 012f154d449..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeeder.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -*- Mode: c++ -*- - -#include "iptvfeeder.h" - -// As of yet, this file contains no method implementations diff --git a/mythtv/libs/libmythtv/iptv/iptvfeeder.h b/mythtv/libs/libmythtv/iptv/iptvfeeder.h deleted file mode 100644 index 058793b7d59..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeeder.h +++ /dev/null @@ -1,57 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeeder - * Copyright (c) 2006 by Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_FEEDER_H_ -#define _IPTV_FEEDER_H_ - -class QString; -class TSDataListener; - -/** \class IPTVFeeder - * \brief Base class for UDP and RTSP data sources for IPTVRecorder. - * - * This is the interface that needs to be implemented to support new - * protocols in the IPTVRecorder. - * - * To register a new implementation, it must be instanciated in - * IPTVFeederWrapper::NewFeeder(). - * - * \sa IPTVFeederWrapper - */ - -class IPTVFeeder -{ - public: - IPTVFeeder() {} - virtual ~IPTVFeeder() {} - - /// \brief Returns true iff the data feed can handle URL - virtual bool CanHandle(const QString &url) const = 0; - /// \brief Returns true if the feeder is currently open - virtual bool IsOpen(void) const = 0; - - /// \brief Inits the feeder and opens the stream identified by url - virtual bool Open(const QString &url) = 0; - /// \brief Closes the stream and frees resources allocated in Open() - virtual void Close(void) = 0; - /** \brief Reads the stream and sends data to its TSDataListener. This - * is a blocking call : it should not exit until Stop() is called. - * \sa Stop(void) - */ - virtual void Run(void) = 0; - /** \brief Tells Run(void) function that it should stop and exit cleanly. - * - * This function blocks until Run(void) has finished up. - * - * \sa Run(void) - */ - virtual void Stop(void) = 0; - - virtual void AddListener(TSDataListener*) = 0; - virtual void RemoveListener(TSDataListener*) = 0; -}; - -#endif // _IPTV_FEEDER_H_ diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederfile.cpp b/mythtv/libs/libmythtv/iptv/iptvfeederfile.cpp deleted file mode 100644 index a2f1331d23e..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederfile.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederFile - * - * Please, don't submit bug reports if it - * can't read your file. Just use MythVideo! - * - * Copyright (c) 2006 by Mike Mironov & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ -#include - -#include "iptvfeederfile.h" - -// Qt headers -#include - -// Live555 headers -#include -#include -#include -#include -#include - -// MythTV headers -#include "iptvmediasink.h" -#include "mythcontext.h" -#include "mythlogging.h" -#include "tspacket.h" - -#define LOC QString("FbFeedFile: ") - - -IPTVFeederFile::IPTVFeederFile() : - _source(NULL), - _sink(NULL) -{ -} - -IPTVFeederFile::~IPTVFeederFile() -{ - Close(); -} - -bool IPTVFeederFile::IsFile(const QString &url) -{ - return url.startsWith("file:", Qt::CaseInsensitive); -} - -bool IPTVFeederFile::Open(const QString &url) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("Open(%1) -- begin").arg(url)); - - QMutexLocker locker(&_lock); - - if (_source) - { - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end 1"); - return true; - } - - QUrl parse(url); - if (parse.path().isEmpty() || (parse.scheme().toLower() != "file")) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Open() -- end 2"); - return false; - } - - // Begin by setting up our usage environment: - if (!InitEnv()) - return false; - - QString pathstr = parse.toLocalFile(); - QByteArray path = pathstr.toLocal8Bit(); - - _source = ByteStreamFileSource::createNew( - *_live_env, path.constData()); - if (!_source) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Live File Source."); - FreeEnv(); - return false; - } - - _sink = IPTVMediaSink::CreateNew(*_live_env, TSPacket::kSize * 128*1024); - if (!_sink) - { - LOG(VB_GENERAL, LOG_ERR, QString("IPTV # Failed to create sink: %1") - .arg(_live_env->getResultMsg())); - - Medium::close(_source); - _source = NULL; - FreeEnv(); - - return false; - } - - _sink->startPlaying(*_source, NULL, NULL); - vector::iterator it = _listeners.begin(); - for (; it != _listeners.end(); ++it) - _sink->AddListener(*it); - - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end"); - - return true; -} - -void IPTVFeederFile::Close(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin"); - Stop(); - - QMutexLocker locker(&_lock); - - if (_sink) - { - Medium::close(_sink); - _sink = NULL; - } - - if (_source) - { - Medium::close(_source); - _source = NULL; - } - - FreeEnv(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); -} - -void IPTVFeederFile::AddListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - if (!item) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end") - .arg((uint64_t)item,0,16)); - return; - } - - // avoid duplicates - RemoveListener(item); - - // add to local list - QMutexLocker locker(&_lock); - _listeners.push_back(item); - - if (_sink) - _sink->AddListener(item); - - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end") - .arg((uint64_t)item,0,16)); -} - -void IPTVFeederFile::RemoveListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - QMutexLocker locker(&_lock); - vector::iterator it = - find(_listeners.begin(), _listeners.end(), item); - - if (it == _listeners.end()) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 1") - .arg((uint64_t)item,0,16)); - return; - } - - // remove from local list.. - *it = *_listeners.rbegin(); - _listeners.resize(_listeners.size() - 1); - - if (_sink) - _sink->RemoveListener(item); - - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 2") - .arg((uint64_t)item,0,16)); -} diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederfile.h b/mythtv/libs/libmythtv/iptv/iptvfeederfile.h deleted file mode 100644 index ecfe3af9f85..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederfile.h +++ /dev/null @@ -1,44 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederFile - * Copyright (c) 2006 by Mike Mironov & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_FEEDER_FILE_H_ -#define _IPTV_FEEDER_FILE_H_ - -// MythTV headers -#include "iptvfeederlive.h" - -class TSDataListener; -class ByteStreamFileSource; -class IPTVMediaSink; - - -class IPTVFeederFile : public IPTVFeederLive -{ - public: - IPTVFeederFile(); - virtual ~IPTVFeederFile(); - - bool CanHandle(const QString &url) const { return IsFile(url); } - bool IsOpen(void) const { return _source; } - - bool Open(const QString &url); - void Close(void); - - void AddListener(TSDataListener*); - void RemoveListener(TSDataListener*); - - static bool IsFile(const QString &url); - - private: - IPTVFeederFile &operator=(const IPTVFeederFile&); - IPTVFeederFile(const IPTVFeederFile&); - - private: - ByteStreamFileSource *_source; - IPTVMediaSink *_sink; -}; - -#endif //_IPTV_FEEDER_FILE_H_ diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederlive.cpp b/mythtv/libs/libmythtv/iptv/iptvfeederlive.cpp deleted file mode 100644 index 2fe1bd580e2..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederlive.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederLive -- base class for livemedia based IPTVFeeders - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#include "iptvfeederlive.h" - -// MythTV headers -#include "mythlogging.h" -#include "timeoutedtaskscheduler.h" - -#define LOC QString("FbFeedLive:") - - -IPTVFeederLive::IPTVFeederLive() : - _live_env(NULL), _lock(), - _abort(0), _running(false) -{ -} - -IPTVFeederLive::~IPTVFeederLive() -{ -} - -bool IPTVFeederLive::InitEnv(void) -{ - if (_live_env) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "InitEnv, live env. already exits."); - return false; - } - - TaskScheduler *scheduler = new TimeoutedTaskScheduler(500); - if (!scheduler) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Live Scheduler."); - return false; - } - - _live_env = BasicUsageEnvironment::createNew(*scheduler); - if (!_live_env) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Live Environment."); - delete scheduler; - return false; - } - - return true; -} - -void IPTVFeederLive::FreeEnv(void) -{ - if (_live_env) - { - TaskScheduler *scheduler = &_live_env->taskScheduler(); - _live_env->reclaim(); - _live_env = NULL; - if (scheduler) - delete scheduler; - } -} - -void IPTVFeederLive::Run(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Run() -- begin"); - _lock.lock(); - _running = true; - _abort = 0; - _lock.unlock(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Run() -- loop begin"); - if (_live_env) - _live_env->taskScheduler().doEventLoop(&_abort); - LOG(VB_RECORD, LOG_INFO, LOC + "Run() -- loop end"); - - _lock.lock(); - _running = false; - _cond.wakeAll(); - _lock.unlock(); - LOG(VB_RECORD, LOG_INFO, LOC + "Run() -- end"); -} - -void IPTVFeederLive::Stop(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Stop() -- begin"); - QMutexLocker locker(&_lock); - _abort = 0xFF; - - while (_running) - _cond.wait(&_lock, 500); - LOG(VB_RECORD, LOG_INFO, LOC + "Stop() -- end"); -} diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederlive.h b/mythtv/libs/libmythtv/iptv/iptvfeederlive.h deleted file mode 100644 index a86ba13d5f5..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederlive.h +++ /dev/null @@ -1,54 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederLive -- base class for livemedia based IPTVFeeders - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_FEEDER_LIVE_H_ -#define _IPTV_FEEDER_LIVE_H_ - -// C++ headers -#include -using namespace std; - -// Qt headers -#include -#include - -// Mythtv headers -#include "iptvfeeder.h" - -class QString; -class TSDataListener; -class UsageEnvironment; - - -class IPTVFeederLive : public IPTVFeeder -{ - public: - IPTVFeederLive(); - virtual ~IPTVFeederLive(); - - void Run(void); - void Stop(void); - - protected: - bool InitEnv(void); - void FreeEnv(void); - - private: - IPTVFeederLive &operator=(const IPTVFeederLive&); - IPTVFeederLive(const IPTVFeederLive&); - - protected: - UsageEnvironment *_live_env; - mutable QMutex _lock; - vector _listeners; - - private: - char _abort; - bool _running; - QWaitCondition _cond; -}; - -#endif // _IPTV_FEEDER_LIVE_H_ diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederrtp.cpp b/mythtv/libs/libmythtv/iptv/iptvfeederrtp.cpp deleted file mode 100644 index 4e56265f11f..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederrtp.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederRtp - * Copyright (c) 2006 by Mike Mironov & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ -#include - -#include "iptvfeederrtp.h" - -// Qt headers -#include - -// Live555 headers -#include -#include -#include -#include -#include - -// MythTV headers -#include "iptvmediasink.h" -#include "mythcontext.h" -#include "mythlogging.h" -#include "tspacket.h" - -#define LOC QString("IPTVFeedRTP: ") - -IPTVFeederRTP::IPTVFeederRTP() : - _source(NULL), - _sink(NULL) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "ctor -- success"); -} - -IPTVFeederRTP::~IPTVFeederRTP() -{ - LOG(VB_RECORD, LOG_INFO, LOC + "dtor -- begin"); - Close(); - LOG(VB_RECORD, LOG_INFO, LOC + "dtor -- end"); -} - -bool IPTVFeederRTP::IsRTP(const QString &url) -{ - return url.startsWith("rtp://", Qt::CaseInsensitive); -} - -bool IPTVFeederRTP::Open(const QString &url) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("Open(%1) -- begin").arg(url)); - - QMutexLocker locker(&_lock); - - if (_source) - { - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end 1"); - return true; - } - - QUrl parse(url); - if (!parse.isValid() || parse.host().isEmpty() || (-1 == parse.port())) - { - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end 2"); - return false; - } - - struct in_addr addr; - QByteArray host = parse.host().toLatin1(); - addr.s_addr = our_inet_addr(host.constData()); - - // Begin by setting up our usage environment: - if (!InitEnv()) - return false; - - Groupsock *socket = new Groupsock(*_live_env, addr, parse.port(), 0); - if (!socket) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Live RTP Socket."); - FreeEnv(); - return false; - } - - _source = SimpleRTPSource::createNew(*_live_env, socket, 33, 90000, - "video/MP2T", 0, False); - if (!_source) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Live RTP Source."); - - if (socket) - delete socket; - - FreeEnv(); - return false; - } - - _sink = IPTVMediaSink::CreateNew(*_live_env, TSPacket::kSize * 128*1024); - if (!_sink) - { - LOG(VB_GENERAL, LOG_ERR, QString("IPTV # Failed to create sink: %1") - .arg(_live_env->getResultMsg())); - - Medium::close(_source); - _source = NULL; - if (socket) - delete socket; - FreeEnv(); - - return false; - } - - _sink->startPlaying(*_source, NULL, NULL); - vector::iterator it = _listeners.begin(); - for (; it != _listeners.end(); ++it) - _sink->AddListener(*it); - - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end"); - - return true; -} - -void IPTVFeederRTP::Close(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin"); - Stop(); - - QMutexLocker locker(&_lock); - - if (_sink) - { - Medium::close(_sink); - _sink = NULL; - } - - if (_source) - { - Groupsock *socket = _source->RTPgs(); - Medium::close(_source); - _source = NULL; - if (socket) - delete socket; - } - - FreeEnv(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); -} - -void IPTVFeederRTP::AddListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - if (!item) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end") - .arg((uint64_t)item,0,16)); - return; - } - - // avoid duplicates - RemoveListener(item); - - // add to local list - QMutexLocker locker(&_lock); - _listeners.push_back(item); - - if (_sink) - _sink->AddListener(item); - - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end") - .arg((uint64_t)item,0,16)); -} - -void IPTVFeederRTP::RemoveListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - QMutexLocker locker(&_lock); - vector::iterator it = - find(_listeners.begin(), _listeners.end(), item); - - if (it == _listeners.end()) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 1") - .arg((uint64_t)item,0,16)); - return; - } - - // remove from local list.. - *it = *_listeners.rbegin(); - _listeners.resize(_listeners.size() - 1); - - if (_sink) - _sink->RemoveListener(item); - - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 2") - .arg((uint64_t)item,0,16)); -} diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederrtp.h b/mythtv/libs/libmythtv/iptv/iptvfeederrtp.h deleted file mode 100644 index 926a34076ec..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederrtp.h +++ /dev/null @@ -1,43 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederRTP - * Copyright (c) 2006 by Mike Mironov & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_FEEDER_RTP_H_ -#define _IPTV_FEEDER_RTP_H_ - -// MythTV headers -#include "iptvfeederlive.h" - -class SimpleRTPSource; -class IPTVMediaSink; - - -class IPTVFeederRTP : public IPTVFeederLive -{ - public: - IPTVFeederRTP(); - virtual ~IPTVFeederRTP(); - - bool CanHandle(const QString &url) const { return IsRTP(url); } - bool IsOpen(void) const { return _source; } - - bool Open(const QString &url); - void Close(void); - - void AddListener(TSDataListener*); - void RemoveListener(TSDataListener*); - - static bool IsRTP(const QString &url); - - private: - IPTVFeederRTP &operator=(const IPTVFeederRTP&); - IPTVFeederRTP(const IPTVFeederRTP&); - - private: - SimpleRTPSource *_source; - IPTVMediaSink *_sink; -}; - -#endif // _IPTV_FEEDER_RTP_H_ diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederrtsp.cpp b/mythtv/libs/libmythtv/iptv/iptvfeederrtsp.cpp deleted file mode 100644 index 3566b472426..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederrtsp.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederRtsp - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ -#include - -#include "iptvfeederrtsp.h" - -// Live555 headers -#include -#include -#include - -// MythTV headers -#include "iptvmediasink.h" -#include "mythcontext.h" -#include "mythlogging.h" -#include "tspacket.h" - -#define LOC QString("IPTVFeedRTSP:") - -/** \class RTSPData - * \brief Helper class use for static Callback handler - */ -class RTSPData -{ - public: - RTSPData(MediaSubsession *pMediaSubSession) : - mediaSubSession(pMediaSubSession) - { - } - - void SubsessionAfterPlayingCB(void); - void SubsessionByeHandlerCB(void); - - private: - MediaSubsession *mediaSubSession; -}; - -void RTSPData::SubsessionAfterPlayingCB(void) -{ - MediaSubsession *subsession = mediaSubSession; - Medium::close(subsession->sink); - subsession->sink = NULL; -} - -static void sub_after_playing_cb(void *clientData) -{ - ((RTSPData*)clientData)->SubsessionAfterPlayingCB(); -} - -void RTSPData::SubsessionByeHandlerCB(void) -{ - SubsessionAfterPlayingCB(); -} - -static void sub_bye_handler_cb(void *clientData) -{ - ((RTSPData*)clientData)->SubsessionByeHandlerCB(); -} - -////////////////////////////////////////////////////////////////////////////// - -IPTVFeederRTSP::IPTVFeederRTSP() : - _rtsp_client(NULL), - _session(NULL) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "ctor -- success"); -} - -IPTVFeederRTSP::~IPTVFeederRTSP() -{ - LOG(VB_RECORD, LOG_INFO, LOC + "dtor -- begin"); - Close(); - LOG(VB_RECORD, LOG_INFO, LOC + "dtor -- end"); -} - -bool IPTVFeederRTSP::IsRTSP(const QString &url) -{ - return url.startsWith("rtsp://", Qt::CaseInsensitive); -} - -bool IPTVFeederRTSP::Open(const QString &url) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("Open(%1) -- begin").arg(url)); - - QMutexLocker locker(&_lock); - - if (_rtsp_client) - { - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end 1"); - - return true; - } - - // Begin by setting up our usage environment: - if (!InitEnv()) - return false; - - // Create our client object: - _rtsp_client = RTSPClient::createNew(*_live_env, 0, "myRTSP", 0); - if (!_rtsp_client) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("Failed to create RTSP client: %1") - .arg(_live_env->getResultMsg())); - FreeEnv(); - return false; - } - - // Setup URL for the current session - char *sdpDescription = _rtsp_client->describeURL( - url.toLatin1().constData()); - - _rtsp_client->describeStatus(); - - if (!sdpDescription) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("Failed to get a SDP description from URL: %1 %2") - .arg(url).arg(_live_env->getResultMsg())); - return false; - } - - // Create a media session object from this SDP description: - _session = MediaSession::createNew(*_live_env, sdpDescription); - - delete[] sdpDescription; - - if (!_session) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("Failed to create MediaSession: %1") - .arg(_live_env->getResultMsg())); - return false; - } - else if (!_session->hasSubsessions()) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "This session has no media subsessions"); - Close(); - return false; - } - - // Then, setup the "RTPSource"s for the session: - MediaSubsessionIterator iter(*_session); - MediaSubsession *subsession; - bool madeProgress = false; - - while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */ - { - if (!subsession->initiate(-1)) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("Can't create receiver for: %1 / %2 subsession: %3") - .arg(subsession->mediumName()) - .arg(subsession->codecName()) - .arg(_live_env->getResultMsg())); - } - else - { - madeProgress = true; - - if (subsession->rtpSource() != NULL) - { - unsigned const thresh = 1000000; // 1 second - subsession->rtpSource()-> - setPacketReorderingThresholdTime(thresh); - } - } - } - - if (!madeProgress) - return false; - - // Perform additional 'setup' on each subsession, before playing them: - madeProgress = false; - iter.reset(); - while ((subsession = iter.next()) != NULL) - { - if (subsession->clientPortNum() == 0) - continue; // port # was not set - - if (_rtsp_client->setupMediaSubsession(*subsession, false, false)) - { - madeProgress = true; - } - else - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("Failed to setup: %1 %2 : %3") - .arg(subsession->mediumName()) - .arg(subsession->codecName()) - .arg(_live_env->getResultMsg())); - } - } - - if (!madeProgress) - return false; - - // Create and start "FileSink"s for each subsession: - // FileSink while receive Mpeg2 TS Data & will feed them to mythtv - madeProgress = false; - iter.reset(); - - while ((subsession = iter.next())) /* <- extra braces for pedantic gcc */ - { - if (!subsession->readSource()) - continue; // was not initiated - - IPTVMediaSink *iptvMediaSink = IPTVMediaSink::CreateNew( - *_live_env, TSPacket::kSize * 128*1024); - - subsession->sink = iptvMediaSink; - if (!subsession->sink) - { - LOG(VB_GENERAL, LOG_ERR, QString("IPTV # Failed to create sink: %1") - .arg(_live_env->getResultMsg())); - } - - vector::iterator it = _listeners.begin(); - for (; it != _listeners.end(); ++it) - iptvMediaSink->AddListener(*it); - - subsession->sink->startPlaying(*(subsession->readSource()), - sub_after_playing_cb, - new RTSPData(subsession)); - - if (subsession->rtcpInstance()) - { - subsession->rtcpInstance()->setByeHandler( - sub_bye_handler_cb, new RTSPData(subsession)); - } - - madeProgress = true; - } - - if (!madeProgress) - return false; - - // Setup player - if (!(_rtsp_client->playMediaSession(*_session))) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("Failed to start playing session: %1") - .arg(_live_env->getResultMsg())); - return false; - } - - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end"); - return true; -} - -void IPTVFeederRTSP::Close(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin"); - Stop(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- middle 1"); - - _lock.lock(); - if (_session) - { - // Ensure RTSP cleanup, remove old RTSP session - MediaSubsessionIterator iter(*_session); - MediaSubsession *subsession; - while ((subsession = iter.next())) /*<-extra braces for pedantic gcc*/ - { - Medium::close(subsession->sink); - subsession->sink = NULL; - } - - _rtsp_client->teardownMediaSession(*_session); - - // Close all RTSP descriptor - Medium::close(_session); - _session = NULL; - } - _lock.unlock(); - - if (_rtsp_client) - { - Medium::close(_rtsp_client); - _rtsp_client = NULL; - } - - FreeEnv(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); -} - -void IPTVFeederRTSP::AddListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - if (!item) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end 0") - .arg((uint64_t)item,0,16)); - return; - } - - // avoid duplicates - RemoveListener(item); - - // add to local list - QMutexLocker locker(&_lock); - _listeners.push_back(item); - - // if there is a session, add to each subsession->sink - if (!_session) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end 1") - .arg((uint64_t)item,0,16)); - return; - } - - MediaSubsessionIterator mit(*_session); - MediaSubsession *subsession; - while ((subsession = mit.next())) /* <- extra braces for pedantic gcc */ - { - IPTVMediaSink *sink = NULL; - if ((sink = dynamic_cast(subsession->sink))) - sink->AddListener(item); - } - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end 2") - .arg((uint64_t)item,0,16)); -} - -void IPTVFeederRTSP::RemoveListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- begin") - .arg((uint64_t)item,0,16));; - QMutexLocker locker(&_lock); - vector::iterator it = - find(_listeners.begin(), _listeners.end(), item); - - if (it == _listeners.end()) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 1") - .arg((uint64_t)item,0,16)); - return; - } - - // remove from local list.. - *it = *_listeners.rbegin(); - _listeners.resize(_listeners.size() - 1); - - // if there is a session, remove from each subsession->sink - if (!_session) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 2") - .arg((uint64_t)item,0,16)); - return; - } - - MediaSubsessionIterator mit(*_session); - MediaSubsession *subsession; - while ((subsession = mit.next())) /* <- extra braces for pedantic gcc */ - { - IPTVMediaSink *sink = NULL; - if ((sink = dynamic_cast(subsession->sink))) - sink->RemoveListener(item); - } - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 3") - .arg((uint64_t)item,0,16)); -} diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederrtsp.h b/mythtv/libs/libmythtv/iptv/iptvfeederrtsp.h deleted file mode 100644 index cd1eb389371..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederrtsp.h +++ /dev/null @@ -1,42 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederRtsp - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_FEEDER_RTSP_H_ -#define _IPTV_FEEDER_RTSP_H_ - -// MythTV headers -#include "iptvfeederlive.h" - -class RTSPClient; -class MediaSession; - -class IPTVFeederRTSP : public IPTVFeederLive -{ - public: - IPTVFeederRTSP(); - virtual ~IPTVFeederRTSP(); - - bool CanHandle(const QString &url) const { return IsRTSP(url); } - bool IsOpen(void) const { return _session; } - - bool Open(const QString &url); - void Close(void); - - void AddListener(TSDataListener*); - void RemoveListener(TSDataListener*); - - static bool IsRTSP(const QString &url); - - private: - IPTVFeederRTSP &operator=(const IPTVFeederRTSP&); - IPTVFeederRTSP(const IPTVFeederRTSP&); - - private: - RTSPClient *_rtsp_client; - MediaSession *_session; -}; - -#endif // _IPTV_FEEDER_RTSP_H_ diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederudp.cpp b/mythtv/libs/libmythtv/iptv/iptvfeederudp.cpp deleted file mode 100644 index 7072b8ce515..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederudp.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederUdp - * Copyright (c) 2006 by Mike Mironov & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ -#define _INC_ERRNO - -#include - -#include "iptvfeederudp.h" - -// Qt headers -#include - -// Live555 headers -#include -#include -#include -#include -#include - -// MythTV headers -#include "iptvmediasink.h" -#include "mythcontext.h" -#include "mythlogging.h" -#include "tspacket.h" - -#define LOC QString("IPTVFeedUDP: ") - -IPTVFeederUDP::IPTVFeederUDP() : - _source(NULL), - _sink(NULL) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "ctor -- success"); -} - -IPTVFeederUDP::~IPTVFeederUDP() -{ - LOG(VB_RECORD, LOG_INFO, LOC + "dtor -- begin"); - Close(); - LOG(VB_RECORD, LOG_INFO, LOC + "dtor -- end"); -} - -bool IPTVFeederUDP::IsUDP(const QString &url) -{ - return url.startsWith("udp://", Qt::CaseInsensitive); -} - -bool IPTVFeederUDP::Open(const QString &url) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("Open(%1) -- begin").arg(url)); - - QMutexLocker locker(&_lock); - - if (_source) - { - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end 1"); - return true; - } - - QUrl parse(url); - if (!parse.isValid() || parse.host().isEmpty() || (-1 == parse.port())) - { - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end 2"); - return false; - } - - struct in_addr addr; - QByteArray host = parse.host().toLatin1(); - addr.s_addr = our_inet_addr(host.constData()); - - // Begin by setting up our usage environment: - if (!InitEnv()) - return false; - - ReceivingSocketAddr = our_inet_addr(parse.host().toLatin1()); - - Groupsock *socket = new Groupsock(*_live_env, addr, parse.port(), 0); - if (!socket) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Live UDP Socket."); - FreeEnv(); - return false; - } - _source = BasicUDPSource::createNew(*_live_env, socket); - if (!_source) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create Live UDP Source."); - - if (socket) - delete socket; - - FreeEnv(); - return false; - } - - _sink = IPTVMediaSink::CreateNew(*_live_env, TSPacket::kSize * 128*1024); - if (!_sink) - { - LOG(VB_GENERAL, LOG_ERR, QString("IPTV # Failed to create sink: %1") - .arg(_live_env->getResultMsg())); - - Medium::close(_source); - _source = NULL; - if (socket) - delete socket; - FreeEnv(); - - return false; - } - - _sink->startPlaying(*_source, NULL, NULL); - vector::iterator it = _listeners.begin(); - for (; it != _listeners.end(); ++it) - _sink->AddListener(*it); - - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end"); - - return true; -} - -void IPTVFeederUDP::Close(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin"); - Stop(); - - QMutexLocker locker(&_lock); - - if (_sink) - { - Medium::close(_sink); - _sink = NULL; - } - - if (_source) - { - Groupsock *socket = _source->gs(); - Medium::close(_source); - _source = NULL; - if (socket) - delete socket; - } - - FreeEnv(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); -} - -void IPTVFeederUDP::AddListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - if (!item) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end") - .arg((uint64_t)item,0,16)); - return; - } - - // avoid duplicates - RemoveListener(item); - - // add to local list - QMutexLocker locker(&_lock); - _listeners.push_back(item); - - if (_sink) - _sink->AddListener(item); - - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end") - .arg((uint64_t)item,0,16)); -} - -void IPTVFeederUDP::RemoveListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - QMutexLocker locker(&_lock); - vector::iterator it = - find(_listeners.begin(), _listeners.end(), item); - - if (it == _listeners.end()) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 1") - .arg((uint64_t)item,0,16)); - return; - } - - // remove from local list.. - *it = *_listeners.rbegin(); - _listeners.resize(_listeners.size() - 1); - - if (_sink) - _sink->RemoveListener(item); - - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 2") - .arg((uint64_t)item,0,16)); -} diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederudp.h b/mythtv/libs/libmythtv/iptv/iptvfeederudp.h deleted file mode 100644 index 48210f021a5..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederudp.h +++ /dev/null @@ -1,39 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederUDP - * Copyright (c) 2006 by Mike Mironov & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_FEEDER_UDP_H_ -#define _IPTV_FEEDER_UDP_H_ - -// MythTV headers -#include "iptvfeederlive.h" - -class BasicUDPSource; -class IPTVMediaSink; - - -class IPTVFeederUDP : public IPTVFeederLive -{ - public: - IPTVFeederUDP(); - virtual ~IPTVFeederUDP(); - - bool CanHandle(const QString &url) const { return IsUDP(url); } - bool IsOpen(void) const { return _source; } - - bool Open(const QString &url); - void Close(void); - - void AddListener(TSDataListener*); - void RemoveListener(TSDataListener*); - - static bool IsUDP(const QString &url); - - private: - BasicUDPSource *_source; - IPTVMediaSink *_sink; -}; - -#endif // _IPTV_FEEDER_UDP_H_ diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederwrapper.cpp b/mythtv/libs/libmythtv/iptv/iptvfeederwrapper.cpp deleted file mode 100644 index c2f80a6e058..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederwrapper.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederWrapper - * Copyright (c) 2006 by Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -// C++ headers -#include -using namespace std; - -// MythTV headers -#include "iptvfeederwrapper.h" - -#include "iptvfeeder.h" -#include "iptvfeederrtsp.h" -#include "iptvfeederudp.h" -#include "iptvfeederrtp.h" -#include "iptvfeederfile.h" -#include "mythcontext.h" -#include "mythlogging.h" - -#define LOC QString("IPTVFeed: ") - - -IPTVFeederWrapper::IPTVFeederWrapper() : - _feeder(NULL), _url(QString::null), _lock() -{ -} - -IPTVFeederWrapper::~IPTVFeederWrapper() -{ - if (_feeder) - { - _feeder->Stop(); - _feeder->Close(); - delete _feeder; - _feeder = NULL; - } -} - -bool IPTVFeederWrapper::InitFeeder(const QString &url) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Init() -- begin"); - QMutexLocker locker(&_lock); - - if (_feeder && _feeder->CanHandle(url)) - { - _url = url; - _url.detach(); - LOG(VB_RECORD, LOG_INFO, LOC + "Init() -- end 0"); - - return true; - } - - IPTVFeeder *tmp_feeder = NULL; - if (IPTVFeederRTSP::IsRTSP(url)) - { - tmp_feeder = new IPTVFeederRTSP(); - } - else if (IPTVFeederUDP::IsUDP(url)) - { - tmp_feeder = new IPTVFeederUDP(); - } - else if (IPTVFeederRTP::IsRTP(url)) - { - tmp_feeder = new IPTVFeederRTP(); - } - else if (IPTVFeederFile::IsFile(url)) - { - tmp_feeder = new IPTVFeederFile(); - } - else - { - LOG(VB_RECORD, LOG_ERR, LOC + - QString("Init() -- unhandled url (%1)").arg(url)); - - return false; - } - - if (_feeder) - delete _feeder; - - _feeder = tmp_feeder; - - _url = url; - _url.detach(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Init() -- adding listeners"); - - vector::iterator it = _listeners.begin(); - for (; it != _listeners.end(); ++it) - _feeder->AddListener(*it); - - LOG(VB_RECORD, LOG_INFO, LOC + "Init() -- end 1"); - - return true; -} - - -bool IPTVFeederWrapper::Open(const QString& url) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- begin"); - - bool result = InitFeeder(url) && _feeder->Open(_url); - - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- end"); - - return result; -} - -bool IPTVFeederWrapper::IsOpen(void) const -{ - LOG(VB_RECORD, LOG_INFO, LOC + "IsOpen() -- begin"); - - bool result = _feeder && _feeder->IsOpen(); - - LOG(VB_RECORD, LOG_INFO, LOC + "IsOpen() -- end"); - - return result; -} - -void IPTVFeederWrapper::Close(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin"); - - if (_feeder) - _feeder->Close(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); -} - -void IPTVFeederWrapper::Run(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Run() -- begin"); - - if (_feeder) - _feeder->Run(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Run() -- end"); -} - -void IPTVFeederWrapper::Stop(void) -{ - LOG(VB_RECORD, LOG_INFO, LOC + "Stop() -- begin"); - - if (_feeder) - _feeder->Stop(); - - LOG(VB_RECORD, LOG_INFO, LOC + "Stop() -- end"); -} - -void IPTVFeederWrapper::AddListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - - if (!item) - { - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end 0") - .arg((uint64_t)item,0,16)); - return; - } - - QMutexLocker locker(&_lock); - vector::iterator it = - find(_listeners.begin(), _listeners.end(), item); - if (it == _listeners.end()) // avoid duplicates - { - _listeners.push_back(item); - if (_feeder) - _feeder->AddListener(item); - } - - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end 1") - .arg((uint64_t)item,0,16)); -} - -void IPTVFeederWrapper::RemoveListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - - QMutexLocker locker(&_lock); - vector::iterator it = - find(_listeners.begin(), _listeners.end(), item); - - if (it == _listeners.end()) - { - LOG(VB_RECORD, LOG_ERR, LOC + QString("RemoveListener(0x%1) -- end " - "(not found)") - .arg((uint64_t)item,0,16)); - - return; - } - - // remove from local list.. - *it = *_listeners.rbegin(); - _listeners.resize(_listeners.size() - 1); - if (_feeder) - _feeder->RemoveListener(item); - - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end (ok, " - "removed)") - .arg((uint64_t)item,0,16)); -} diff --git a/mythtv/libs/libmythtv/iptv/iptvfeederwrapper.h b/mythtv/libs/libmythtv/iptv/iptvfeederwrapper.h deleted file mode 100644 index 606c2a800dd..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvfeederwrapper.h +++ /dev/null @@ -1,54 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVFeederWrapper - * Copyright (c) 2006 by Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_FEEDER_WRAPPER_H_ -#define _IPTV_FEEDER_WRAPPER_H_ - -#include -using namespace std; - -#include -#include - -class IPTVFeeder; -class TSDataListener; - -/** \class IPTVFeederWrapper - * \brief Helper class for dealing with IPTVFeeder instances. - */ -class IPTVFeederWrapper -{ - public: - IPTVFeederWrapper(); - ~IPTVFeederWrapper(); - - public: - bool IsOpen(void) const; - - bool Open(const QString &url); - void Close(void); - - void Run(void); - void Stop(void); - - void AddListener(TSDataListener*); - void RemoveListener(TSDataListener*); - - private: - bool InitFeeder(const QString &url); - - private: - IPTVFeeder *_feeder; - QString _url; - mutable QMutex _lock; ///< Lock used to coordinate threads - vector _listeners; - - private: - IPTVFeederWrapper &operator=(const IPTVFeederWrapper&); - IPTVFeederWrapper(const IPTVFeederWrapper&); -}; - -#endif // _IPTV_FEEDER_WRAPPER_H_ diff --git a/mythtv/libs/libmythtv/iptv/iptvmediasink.cpp b/mythtv/libs/libmythtv/iptv/iptvmediasink.cpp deleted file mode 100644 index f6147a01fd6..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvmediasink.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVMediaSink - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ -#include - -#include "mythcontext.h" -#include "mythlogging.h" -#include "iptvmediasink.h" -#include "streamlisteners.h" - -#define LOC QString("IPTVSink:") - -IPTVMediaSink::IPTVMediaSink(UsageEnvironment &env, - unsigned int bufferSize) : - MediaSink(env), - _buf(NULL), _buf_size(bufferSize), - _env(env), _lock(QMutex::Recursive) -{ - _buf = new unsigned char[_buf_size]; -} - -IPTVMediaSink::~IPTVMediaSink() -{ - if (_buf) - { - delete[] _buf; - _buf = NULL; - } -} - -IPTVMediaSink *IPTVMediaSink::CreateNew(UsageEnvironment &env, - unsigned int bufferSize) -{ - return new IPTVMediaSink(env, bufferSize); -} - -Boolean IPTVMediaSink::continuePlaying(void) -{ - if (fSource) - { - fSource->getNextFrame(_buf, _buf_size, afterGettingFrame, this, - onSourceClosure, this); - return True; - } - - return False; -} - -void IPTVMediaSink::afterGettingFrame( - void* clientData, - unsigned int frameSize, - unsigned int /*numTruncatedBytes*/, - struct timeval presentationTime, - unsigned int /*durationInMicroseconds*/) -{ - IPTVMediaSink *sink = (IPTVMediaSink*) clientData; - sink->afterGettingFrame1(frameSize, presentationTime); -} - -void IPTVMediaSink::afterGettingFrame1(unsigned int frameSize, - struct timeval) -{ - _lock.lock(); - vector::iterator it = _listeners.begin(); - for (; it != _listeners.end(); ++it) - (*it)->AddData(_buf, frameSize); - _lock.unlock(); - - continuePlaying(); -} - -void IPTVMediaSink::AddListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- begin") - .arg((uint64_t)item,0,16)); - if (item) - { - RemoveListener(item); - QMutexLocker locker(&_lock); - _listeners.push_back(item); - } - LOG(VB_RECORD, LOG_INFO, LOC + QString("AddListener(0x%1) -- end") - .arg((uint64_t)item,0,16)); -} - -void IPTVMediaSink::RemoveListener(TSDataListener *item) -{ - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- begin 1") - .arg((uint64_t)item,0,16)); - QMutexLocker locker(&_lock); - vector::iterator it = - find(_listeners.begin(), _listeners.end(), item); - if (it != _listeners.end()) - { - *it = *_listeners.rbegin(); - _listeners.resize(_listeners.size() - 1); - } - LOG(VB_RECORD, LOG_INFO, LOC + QString("RemoveListener(0x%1) -- end 6") - .arg((uint64_t)item,0,16)); -} - -/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythtv/iptv/iptvmediasink.h b/mythtv/libs/libmythtv/iptv/iptvmediasink.h deleted file mode 100644 index e5201ea8d2a..00000000000 --- a/mythtv/libs/libmythtv/iptv/iptvmediasink.h +++ /dev/null @@ -1,64 +0,0 @@ -/** -*- Mode: c++ -*- - * IPTVMediaSink - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _IPTV_MEDIASINK_H_ -#define _IPTV_MEDIASINK_H_ - -#include -using namespace std; - -#include - -#include - -class TSDataListener; - -// ============================================================================ -// IPTVMediaSink : Helper class use to receive RTSP data from socket. -// ============================================================================ -class IPTVMediaSink : public MediaSink -{ - public: - static IPTVMediaSink *CreateNew(UsageEnvironment &env, - unsigned bufferSize); - - void AddListener(TSDataListener*); - void RemoveListener(TSDataListener*); - - protected: - IPTVMediaSink(UsageEnvironment &env, - unsigned int bufferSize); - virtual ~IPTVMediaSink(); - - virtual void afterGettingFrame1(unsigned frameSize, - struct timeval presentationTime); - - static void afterGettingFrame(void *clientData, - unsigned int frameSize, - unsigned int numTruncatedBytes, - struct timeval presentationTime, - unsigned int durationInMicroseconds); - - private: - virtual Boolean continuePlaying(void); - - private: - unsigned char *_buf; - unsigned int _buf_size; - UsageEnvironment &_env; - vector _listeners; - mutable QMutex _lock; - - private: - // avoid default contructors & operator= - IPTVMediaSink(); - IPTVMediaSink(const IPTVMediaSink&); - IPTVMediaSink &operator=(const IPTVMediaSink&); -}; - -#endif // _IPTV_MEDIASINK_H_ - -/* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythtv/iptv/timeoutedtaskscheduler.cpp b/mythtv/libs/libmythtv/iptv/timeoutedtaskscheduler.cpp deleted file mode 100644 index 308f20196f9..00000000000 --- a/mythtv/libs/libmythtv/iptv/timeoutedtaskscheduler.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/** -*- Mode: c++ -*- - * TimeoutedTaskScheduler - * Copyright (c) 2006 by Mike Mironov - * Distributed as part of MythTV under GPL v2 and later. - */ - -#include "timeoutedtaskscheduler.h" - - -TimeoutedTaskScheduler::TimeoutedTaskScheduler(unsigned int maxDelayTimeMS) : - _maxDelayTimeUS(maxDelayTimeMS * 1000) -{ -} - -void TimeoutedTaskScheduler::doEventLoop(char *watchVariable) -{ - // Repeatedly loop, handling readble sockets and timed events: - while (!watchVariable || !(*watchVariable)) - { - SingleStep(_maxDelayTimeUS); - } -} diff --git a/mythtv/libs/libmythtv/iptv/timeoutedtaskscheduler.h b/mythtv/libs/libmythtv/iptv/timeoutedtaskscheduler.h deleted file mode 100644 index 8a968c8127e..00000000000 --- a/mythtv/libs/libmythtv/iptv/timeoutedtaskscheduler.h +++ /dev/null @@ -1,26 +0,0 @@ -/** -*- Mode: c++ -*- - * TimeoutedTaskScheduler - * Copyright (c) 2006 by Mike Mironov - * Distributed as part of MythTV under GPL v2 and later. - */ - -#ifndef _TIMEOUTEDTASKSCHEDULER_H_ -#define _TIMEOUTEDTASKSCHEDULER_H_ - -// Live555 headers -#include - - -class TimeoutedTaskScheduler : public BasicTaskScheduler -{ - public: - TimeoutedTaskScheduler(unsigned int maxDelayTimeMS); - - public: - virtual void doEventLoop(char *watchVariable); - - private: - unsigned int _maxDelayTimeUS; -}; - -#endif //_TIMEOUTEDTASKSCHEDULER_H_ diff --git a/mythtv/libs/libmythtv/iptvchannel.cpp b/mythtv/libs/libmythtv/iptvchannel.cpp index 1b4bc2cfeba..7508606e5fa 100644 --- a/mythtv/libs/libmythtv/iptvchannel.cpp +++ b/mythtv/libs/libmythtv/iptvchannel.cpp @@ -1,190 +1,74 @@ /** -*- Mode: c++ -*- * IPTVChannel - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars + * Copyright (c) 2006-2009 Silicondust Engineering Ltd, and + * Daniel Thor Kristjansson + * Copyright (c) 2012 Digital Nirvana, Inc. * Distributed as part of MythTV under GPL v2 and later. */ -#include "iptvchannel.h" - // MythTV headers -#include "mythdb.h" +#include "iptvchannel.h" #include "mythlogging.h" -#include "iptvchannelfetcher.h" -#include "iptvfeederwrapper.h" +#include "mythdb.h" #define LOC QString("IPTVChan(%1): ").arg(GetCardID()) -IPTVChannel::IPTVChannel(TVRec *parent, - const QString &videodev) - : DTVChannel(parent), - m_videodev(videodev), - m_feeder(new IPTVFeederWrapper()), - m_lock(QMutex::Recursive) +IPTVChannel::IPTVChannel(TVRec *rec) : + DTVChannel(rec), m_open(false) { - m_videodev.detach(); LOG(VB_CHANNEL, LOG_INFO, LOC + "ctor"); } IPTVChannel::~IPTVChannel() { - LOG(VB_CHANNEL, LOG_INFO, LOC + "dtor -- begin"); - if (m_feeder) - { - delete m_feeder; - m_feeder = NULL; - } - LOG(VB_CHANNEL, LOG_INFO, LOC + "dtor -- end"); + LOG(VB_GENERAL, LOG_INFO, LOC + "dtor"); } bool IPTVChannel::Open(void) { - LOG(VB_CHANNEL, LOG_INFO, LOC + "Open() -- begin"); + LOG(VB_GENERAL, LOG_INFO, LOC + "Open()"); + + if (IsOpen()) + return true; + QMutexLocker locker(&m_lock); - LOG(VB_CHANNEL, LOG_INFO, LOC + "Open() -- locked"); if (!InitializeInputs()) { - LOG(VB_GENERAL, LOG_ERR, LOC + "InitializeInputs() failed"); + Close(); return false; } - if (m_freeboxchannels.empty()) - { - QString content = IPTVChannelFetcher::DownloadPlaylist( - m_videodev, true); - m_freeboxchannels = IPTVChannelFetcher::ParsePlaylist(content); - LOG(VB_GENERAL, LOG_NOTICE, LOC + QString("Loaded %1 channels from %2") - .arg(m_freeboxchannels.size()) .arg(m_videodev)); - } + m_open = true; - LOG(VB_CHANNEL, LOG_INFO, LOC + "Open() -- end"); - return !m_freeboxchannels.empty(); + return m_open; } void IPTVChannel::Close(void) { - LOG(VB_CHANNEL, LOG_INFO, LOC + "Close() -- begin"); + LOG(VB_GENERAL, LOG_INFO, LOC + "Close()"); QMutexLocker locker(&m_lock); - LOG(VB_CHANNEL, LOG_INFO, LOC + "Close() -- locked"); - //m_freeboxchannels.clear(); - LOG(VB_CHANNEL, LOG_INFO, LOC + "Close() -- end"); + m_open = false; } bool IPTVChannel::IsOpen(void) const { - LOG(VB_CHANNEL, LOG_INFO, LOC + "IsOpen() -- begin"); QMutexLocker locker(&m_lock); - LOG(VB_CHANNEL, LOG_INFO, LOC + "IsOpen() -- locked"); - LOG(VB_CHANNEL, LOG_INFO, LOC + "IsOpen() -- end"); - return !m_freeboxchannels.empty(); + LOG(VB_GENERAL, LOG_INFO, LOC + QString("IsOpen() -> %1") + .arg(m_open ? "true" : "false")); + return m_open; } -bool IPTVChannel::SetChannelByString(const QString &channum) +bool IPTVChannel::Tune(const QString &freqid, int finetune) { - LOG(VB_CHANNEL, LOG_INFO, LOC + "SetChannelByString() -- begin"); - QMutexLocker locker(&m_lock); - LOG(VB_CHANNEL, LOG_INFO, LOC + "SetChannelByString() -- locked"); - - InputMap::const_iterator it = m_inputs.find(m_currentInputID); - if (it == m_inputs.end()) - return false; - - uint mplexid_restriction; - if (!IsInputAvailable(m_currentInputID, mplexid_restriction)) - return false; - - // Verify that channel exists - if (!GetChanInfo(channum).isValid()) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("SetChannelByString(%1)").arg(channum) + - " Invalid channel"); - return false; - } - - // Set the current channum to the new channel's channum - QString tmp = channum; tmp.detach(); - m_curchannelname = tmp; + (void) finetune; - // Set the dtv channel info for any additional multiplex tuning - SetDTVInfo(/*atsc_major*/ 0, /*atsc_minor*/ 0, - /*netid*/ 0, - /*tsid*/ 0, /*mpeg_prog_num*/ 1); + LOG(VB_GENERAL, LOG_INFO, LOC + QString("Tune(%1) TO BE IMPLEMENTED") + .arg(freqid)); - HandleScript(channum /* HACK treat channum as freqid */); - - LOG(VB_CHANNEL, LOG_INFO, LOC + "SetChannelByString() -- end"); - return true; -} - -IPTVChannelInfo IPTVChannel::GetChanInfo( - const QString &channum, uint sourceid) const -{ - LOG(VB_CHANNEL, LOG_INFO, LOC + "GetChanInfo() -- begin"); - QMutexLocker locker(&m_lock); - LOG(VB_CHANNEL, LOG_INFO, LOC + "GetChanInfo() -- locked"); - - IPTVChannelInfo dummy; - QString msg = LOC + QString("GetChanInfo(%1) failed").arg(channum); - - if (channum.isEmpty()) - { - LOG(VB_GENERAL, LOG_ERR, msg); - return dummy; - } - - if (!sourceid) - { - InputMap::const_iterator it = m_inputs.find(m_currentInputID); - if (it == m_inputs.end()) - { - LOG(VB_GENERAL, LOG_ERR, msg); - return dummy; - } - sourceid = (*it)->sourceid; - } - - MSqlQuery query(MSqlQuery::InitCon()); - query.prepare( - "SELECT freqid, name " - "FROM channel " - "WHERE channum = :CHANNUM AND " - " sourceid = :SOURCEID"); - - query.bindValue(":CHANNUM", channum); - query.bindValue(":SOURCEID", sourceid); - - if (!query.exec() || !query.isActive()) - { - MythDB::DBError("fetching chaninfo", query); - LOG(VB_GENERAL, LOG_ERR, msg); - return dummy; - } - - while (query.next()) - { - // Try to map freqid or name to a channel in the map - const QString freqid = query.value(0).toString(); - fbox_chan_map_t::const_iterator it; - if (!freqid.isEmpty()) - { - it = m_freeboxchannels.find(freqid); - if (it != m_freeboxchannels.end()) - return *it; - } - - // Try to map name to a channel in the map - const QString name = query.value(1).toString(); - for (it = m_freeboxchannels.begin(); - it != m_freeboxchannels.end(); ++it) - { - if ((*it).m_name == name) - return *it; - } - } + // TODO IMPLEMENT - LOG(VB_GENERAL, LOG_ERR, msg); - return dummy; + return false; } /* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythtv/iptvchannel.h b/mythtv/libs/libmythtv/iptvchannel.h index f54169eb544..46f6ac46e60 100644 --- a/mythtv/libs/libmythtv/iptvchannel.h +++ b/mythtv/libs/libmythtv/iptvchannel.h @@ -1,60 +1,37 @@ /** -*- Mode: c++ -*- * IPTVChannel - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars + * Copyright (c) 2006-2009 Silicondust Engineering Ltd, and + * Daniel Thor Kristjansson + * Copyright (c) 2012 Digital Nirvana, Inc. * Distributed as part of MythTV under GPL v2 and later. */ #ifndef _IPTV_CHANNEL_H_ #define _IPTV_CHANNEL_H_ -#include +// Qt headers #include +// MythTV headers #include "dtvchannel.h" -#include "iptvchannelinfo.h" - -class IPTVFeederWrapper; class IPTVChannel : public DTVChannel { - friend class IPTVSignalMonitor; - friend class IPTVRecorder; - public: - IPTVChannel(TVRec *parent, const QString &videodev); + IPTVChannel(TVRec*); ~IPTVChannel(); // Commands bool Open(void); void Close(void); - bool SetChannelByString(const QString &channum); + bool Tune(const QString &freqid, int finetune); // Gets bool IsOpen(void) const; - // Channel scanning stuff - bool Tune(const DTVMultiplex&, QString) { return true; } - - private: - IPTVChannelInfo GetCurrentChanInfo(void) const - { return GetChanInfo(m_curchannelname); } - - IPTVFeederWrapper *GetFeeder(void) { return m_feeder; } - const IPTVFeederWrapper *GetFeeder(void) const { return m_feeder; } - - IPTVChannelInfo GetChanInfo( - const QString &channum, uint sourceid = 0) const; - - private: - QString m_videodev; - fbox_chan_map_t m_freeboxchannels; - IPTVFeederWrapper *m_feeder; - mutable QMutex m_lock; - private: - IPTVChannel &operator=(const IPTVChannel&); //< avoid default impl - IPTVChannel(const IPTVChannel&); //< avoid default impl - IPTVChannel(); //< avoid default impl + mutable QMutex m_lock; + volatile bool m_open; }; #endif // _IPTV_CHANNEL_H_ diff --git a/mythtv/libs/libmythtv/iptvrecorder.cpp b/mythtv/libs/libmythtv/iptvrecorder.cpp index 8ff60e4d9cc..68d27aa3259 100644 --- a/mythtv/libs/libmythtv/iptvrecorder.cpp +++ b/mythtv/libs/libmythtv/iptvrecorder.cpp @@ -1,113 +1,64 @@ -// -*- Mode: c++ -*- -/** +/** -*- Mode: c++ -*- * IPTVRecorder - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars + * Copyright (c) 2006-2009 Silicondust Engineering Ltd, and + * Daniel Thor Kristjansson + * Copyright (c) 2012 Digital Nirvana, Inc. * Distributed as part of MythTV under GPL v2 and later. */ -#include - // MythTV headers -#include "mpegstreamdata.h" -#include "tspacket.h" -#include "iptvchannel.h" -#include "iptvfeederwrapper.h" #include "iptvrecorder.h" -#include "tv_rec.h" +#include "mpegstreamdata.h" #define LOC QString("IPTVRec: ") -// ============================================================================ -// IPTVRecorder : Processes data from RTSPComms and writes it to disk -// ============================================================================ - IPTVRecorder::IPTVRecorder(TVRec *rec, IPTVChannel *channel) : - DTVRecorder(rec), - _channel(channel) + DTVRecorder(rec), m_channel(channel), m_open(false) { - _channel->GetFeeder()->AddListener(this); } IPTVRecorder::~IPTVRecorder() { StopRecording(); - _channel->GetFeeder()->RemoveListener(this); } bool IPTVRecorder::Open(void) { - LOG(VB_RECORD, LOG_INFO, LOC + "Open() -- begin"); - - if (_channel->GetFeeder()->IsOpen()) - _channel->GetFeeder()->Close(); - - IPTVChannelInfo chaninfo = _channel->GetCurrentChanInfo(); + if (IsOpen()) + { + LOG(VB_GENERAL, LOG_WARNING, LOC + "Card already open"); + return true; + } - if (!chaninfo.isValid()) - _error = "Channel Info is invalid"; - else if (!_channel->GetFeeder()->Open(chaninfo.m_url)) - _error = QString("Failed to open URL %1") - .arg(chaninfo.m_url); + ResetForNewFile(); - LOG(VB_RECORD, LOG_INFO, LOC + QString("Open() -- end err(%1)") - .arg(_error)); + LOG(VB_RECORD, LOG_INFO, LOC + "opened successfully"); - return !IsErrored(); + return true; } -void IPTVRecorder::Close(void) +bool IPTVRecorder::IsOpen(void) const { - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- begin"); - _channel->GetFeeder()->Stop(); - _channel->GetFeeder()->Close(); - LOG(VB_RECORD, LOG_INFO, LOC + "Close() -- end"); + return m_open; } -bool IPTVRecorder::PauseAndWait(int timeout) +void IPTVRecorder::Close(void) { - QMutexLocker locker(&pauseLock); - if (request_pause) - { - if (!IsPaused(true)) - { - _channel->GetFeeder()->Stop(); - _channel->GetFeeder()->Close(); - - paused = true; - pauseWait.wakeAll(); - if (tvrec) - tvrec->RecorderPaused(); - } - - unpauseWait.wait(&pauseLock, timeout); - } - - if (!request_pause && IsPaused(true)) - { - paused = false; - - if (recording && !_channel->GetFeeder()->IsOpen()) - Open(); - - if (_stream_data) - _stream_data->Reset(_stream_data->DesiredProgram()); - - unpauseWait.wakeAll(); - } - - return IsPaused(true); + LOG(VB_RECORD, LOG_INFO, LOC + "Close()"); + m_open = false; } void IPTVRecorder::run(void) { - LOG(VB_RECORD, LOG_INFO, LOC + "run() -- begin"); + LOG(VB_RECORD, LOG_INFO, LOC + "run -- begin"); + if (!Open()) { - _error = "Failed to open IPTV stream"; + _error = "Failed to open IPTVRecorder device"; + LOG(VB_GENERAL, LOG_ERR, LOC + _error); return; } - // Start up... { QMutexLocker locker(&pauseLock); request_recording = true; @@ -115,6 +66,16 @@ void IPTVRecorder::run(void) recordingWait.wakeAll(); } + // Make sure the first things in the file are a PAT & PMT + bool tmp = _wait_for_keyframe_option; + _wait_for_keyframe_option = false; + HandleSingleProgramPAT(_stream_data->PATSingleProgram()); + HandleSingleProgramPMT(_stream_data->PMTSingleProgram()); + _wait_for_keyframe_option = tmp; + + _stream_data->AddAVListener(this); + _stream_data->AddWritingListener(this); + while (IsRecordingRequested() && !IsErrored()) { if (PauseAndWait()) @@ -123,141 +84,32 @@ void IPTVRecorder::run(void) if (!IsRecordingRequested()) break; - if (!_channel->GetFeeder()->IsOpen()) + if (!_input_pmt) { + LOG(VB_GENERAL, LOG_WARNING, LOC + + "Recording will not commence until a PMT is set."); usleep(5000); continue; } - // Go into main RTSP loop, feeding data to AddData - _channel->GetFeeder()->Run(); + // TODO IMPLEMENT -- RTP/UDP reading.. + usleep(100 * 1000); } - // Finish up... - FinishRecording(); + LOG(VB_RECORD, LOG_INFO, LOC + "run -- ending..."); + + _stream_data->RemoveWritingListener(this); + _stream_data->RemoveAVListener(this); + Close(); + FinishRecording(); + QMutexLocker locker(&pauseLock); recording = false; recordingWait.wakeAll(); - LOG(VB_RECORD, LOG_INFO, LOC + "run() -- end"); -} - -// =================================================== -// findTSHeader : find a TS Header in flow -// =================================================== -static int IPTVRecorder_findTSHeader(const unsigned char *data, - uint dataSize) -{ - unsigned int pos = 0; - - while (pos < dataSize) - { - if (data[pos] == 0x47) - return pos; - pos++; - } - - return -1; -} - -// =================================================== -// AddData : feed data from RTSP flow to mythtv -// =================================================== -void IPTVRecorder::AddData(const unsigned char *data, unsigned int dataSize) -{ - unsigned int readIndex = 0; - - // data may be compose from more than one packet, loop to consume all data - while (readIndex < dataSize) - { - // If recorder is paused, stop there - if (IsPaused(false)) - return; - - // Find the next TS Header in data - int tsPos = IPTVRecorder_findTSHeader( - data + readIndex, dataSize - readIndex); - - // if no TS, something bad happens - if (tsPos == -1) - { - LOG(VB_GENERAL, LOG_ERR, LOC + "No TS header."); - break; - } - - // if TS Header not at start of data, we receive out of sync data - if (tsPos > 0) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - QString("TS packet at %1, not in sync.").arg(tsPos)); - } - - // Check if the next packet in buffer is complete : - // packet size is 188 bytes long - if ((dataSize - tsPos - readIndex) < TSPacket::kSize) - { - LOG(VB_GENERAL, LOG_ERR, LOC + - "TS packet at stradles end of buffer."); - break; - } - - // Cast current found TS Packet to TSPacket structure - const void *newData = data + tsPos + readIndex; - ProcessTSPacket(*reinterpret_cast(newData)); - - // follow to next packet - readIndex += tsPos + TSPacket::kSize; - } -} - -bool IPTVRecorder::ProcessTSPacket(const TSPacket& tspacket) -{ - if (!_stream_data) - return true; - - if (tspacket.TransportError() || tspacket.Scrambled()) - return true; - - if (tspacket.HasAdaptationField()) - _stream_data->HandleAdaptationFieldControl(&tspacket); - - if (tspacket.HasPayload()) - { - const unsigned int lpid = tspacket.PID(); - - // Pass or reject packets based on PID, and parse info from them - if (lpid == _stream_data->VideoPIDSingleProgram()) - { - ProgramMapTable *pmt = _stream_data->PMTSingleProgram(); - uint video_stream_type = pmt->StreamType(pmt->FindPID(lpid)); - - if (video_stream_type == StreamID::H264Video) - _buffer_packets = !FindH264Keyframes(&tspacket); - else if (StreamID::IsVideo(video_stream_type)) - _buffer_packets = !FindMPEG2Keyframes(&tspacket); - - if ((video_stream_type != StreamID::H264Video) || _seen_sps) - BufferedWrite(tspacket); - } - else if (_stream_data->IsAudioPID(lpid)) - { - _buffer_packets = !FindAudioKeyframes(&tspacket); - BufferedWrite(tspacket); - } - else if (_stream_data->IsListeningPID(lpid)) - _stream_data->HandleTSTables(&tspacket); - else if (_stream_data->IsWritingPID(lpid)) - BufferedWrite(tspacket); - } - - return true; -} - -void IPTVRecorder::SetStreamData(void) -{ - _stream_data->AddMPEGSPListener(this); + LOG(VB_RECORD, LOG_INFO, LOC + "run -- end"); } /* vim: set expandtab tabstop=4 shiftwidth=4: */ diff --git a/mythtv/libs/libmythtv/iptvrecorder.h b/mythtv/libs/libmythtv/iptvrecorder.h index 5b6c667b724..70195689d4b 100644 --- a/mythtv/libs/libmythtv/iptvrecorder.h +++ b/mythtv/libs/libmythtv/iptvrecorder.h @@ -1,57 +1,35 @@ -// -*- Mode: c++ -*- -/** +/** -*- Mode: c++ -*- * IPTVRecorder - * Copyright (c) 2006 by Laurent Arnal, Benjamin Lerman & Mickaël Remars + * Copyright (c) 2006-2009 Silicondust Engineering Ltd, and + * Daniel Thor Kristjansson + * Copyright (c) 2012 Digital Nirvana, Inc. * Distributed as part of MythTV under GPL v2 and later. */ #ifndef _IPTV_RECORDER_H_ #define _IPTV_RECORDER_H_ -#include - +// MythTV includes #include "dtvrecorder.h" #include "streamlisteners.h" -class QString; class IPTVChannel; -/** \brief Processes data from a IPTVFeeder and writes it to disk. - */ -class IPTVRecorder : public DTVRecorder, public TSDataListener +class IPTVRecorder : public DTVRecorder { - friend class IPTVMediaSink; - public: - IPTVRecorder(TVRec *rec, IPTVChannel *channel); + IPTVRecorder(TVRec*, IPTVChannel*); ~IPTVRecorder(); bool Open(void); + bool IsOpen(void) const; void Close(void); virtual void run(void); - virtual void SetOptionsFromProfile(RecordingProfile*, const QString&, - const QString&, const QString&) {} - - virtual void SetStreamData(void); - - virtual bool IsExternalChannelChangeSupported(void) { return true; } - - private: - bool ProcessTSPacket(const TSPacket &tspacket); - virtual bool PauseAndWait(int timeout = 100); - - // implements TSDataListener - void AddData(const unsigned char *data, unsigned int dataSize); - - private: - IPTVChannel *_channel; - private: - IPTVRecorder &operator=(const IPTVRecorder&); //< avoid default impl - IPTVRecorder(const IPTVRecorder&); //< avoid default impl - IPTVRecorder(); //< avoid default impl + IPTVChannel *m_channel; + bool m_open; }; #endif // _IPTV_RECORDER_H_ diff --git a/mythtv/libs/libmythtv/iptvsignalmonitor.cpp b/mythtv/libs/libmythtv/iptvsignalmonitor.cpp index 04871d56096..9c8fef14ed9 100644 --- a/mythtv/libs/libmythtv/iptvsignalmonitor.cpp +++ b/mythtv/libs/libmythtv/iptvsignalmonitor.cpp @@ -1,12 +1,9 @@ // -*- Mode: c++ -*- -#include - // MythTV headers +#include "iptvsignalmonitor.h" #include "mpegstreamdata.h" #include "iptvchannel.h" -#include "iptvfeederwrapper.h" -#include "iptvsignalmonitor.h" #include "mythlogging.h" #undef DBG_SM @@ -42,12 +39,8 @@ IPTVSignalMonitor::IPTVSignalMonitor(int db_cardnum, DTVSignalMonitor(db_cardnum, _channel, _flags), dtvMonitorRunning(false), tableMonitorThread(NULL) { - bool isLocked = false; - IPTVChannelInfo chaninfo = GetChannel()->GetCurrentChanInfo(); - if (chaninfo.isValid()) - { - isLocked = GetChannel()->GetFeeder()->Open(chaninfo.m_url); - } + // TODO init isLocked + bool isLocked = true; QMutexLocker locker(&statusLock); signalLock.SetValue((isLocked) ? 1 : 0); @@ -59,7 +52,6 @@ IPTVSignalMonitor::IPTVSignalMonitor(int db_cardnum, */ IPTVSignalMonitor::~IPTVSignalMonitor() { - GetChannel()->GetFeeder()->RemoveListener(this); Stop(); } @@ -74,11 +66,9 @@ IPTVChannel *IPTVSignalMonitor::GetChannel(void) void IPTVSignalMonitor::Stop(void) { DBG_SM("Stop", "begin"); - GetChannel()->GetFeeder()->RemoveListener(this); SignalMonitor::Stop(); if (tableMonitorThread) { - GetChannel()->GetFeeder()->Stop(); dtvMonitorRunning = false; tableMonitorThread->wait(); delete tableMonitorThread; @@ -96,9 +86,7 @@ void IPTVSignalMonitor::RunTableMonitor(void) GetStreamData()->AddListeningPID(0); - GetChannel()->GetFeeder()->AddListener(this); - GetChannel()->GetFeeder()->Run(); - GetChannel()->GetFeeder()->RemoveListener(this); + // TODO IMPLEMENT -- RTP/UDP reading.. while (dtvMonitorRunning) usleep(10000); @@ -106,12 +94,6 @@ void IPTVSignalMonitor::RunTableMonitor(void) DBG_SM("Run", "end"); } -void IPTVSignalMonitor::AddData( - const unsigned char *data, unsigned int dataSize) -{ - GetStreamData()->ProcessData((unsigned char*)data, dataSize); -} - /** \fn IPTVSignalMonitor::UpdateValues(void) * \brief Fills in frontend stats and emits status Qt signals. * diff --git a/mythtv/libs/libmythtv/iptvsignalmonitor.h b/mythtv/libs/libmythtv/iptvsignalmonitor.h index eae3d1db2a3..3a54785860c 100644 --- a/mythtv/libs/libmythtv/iptvsignalmonitor.h +++ b/mythtv/libs/libmythtv/iptvsignalmonitor.h @@ -20,7 +20,7 @@ class IPTVTableMonitorThread : public MThread IPTVSignalMonitor *m_parent; }; -class IPTVSignalMonitor : public DTVSignalMonitor, public TSDataListener +class IPTVSignalMonitor : public DTVSignalMonitor { friend class IPTVTableMonitorThread; public: @@ -30,9 +30,6 @@ class IPTVSignalMonitor : public DTVSignalMonitor, public TSDataListener void Stop(void); - // implements TSDataListener - void AddData(const unsigned char *data, unsigned int dataSize); - protected: IPTVSignalMonitor(void); IPTVSignalMonitor(const IPTVSignalMonitor&); diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro index 405fff92b28..199c3b17ef6 100644 --- a/mythtv/libs/libmythtv/libmythtv.pro +++ b/mythtv/libs/libmythtv/libmythtv.pro @@ -24,7 +24,7 @@ DEPENDPATH += ../libmyth ../libmyth/audio DEPENDPATH += ../libmythbase ../libmythhdhomerun DEPENDPATH += ../libmythdvdnav/ DEPENDPATH += ../libmythbluray/ -DEPENDPATH += ./dvbdev ./mpeg ./iptv ./channelscan ./visualisations +DEPENDPATH += ./dvbdev ./mpeg ./rtp ./channelscan ./visualisations DEPENDPATH += ../libmythlivemedia/BasicUsageEnvironment/include DEPENDPATH += ../libmythlivemedia/BasicUsageEnvironment DEPENDPATH += ../libmythlivemedia/groupsock/include @@ -566,28 +566,12 @@ using_backend { DEFINES += USING_FIREWIRE } - # Support for MPEG2 TS streams (including FreeBox http://adsl.free.fr/) - using_iptv { - HEADERS += iptvchannel.h iptvrecorder.h - HEADERS += iptvsignalmonitor.h - HEADERS += iptv/iptvchannelfetcher.h iptv/iptvchannelinfo.h - HEADERS += iptv/iptvmediasink.h - HEADERS += iptv/iptvfeeder.h iptv/iptvfeederwrapper.h - HEADERS += iptv/iptvfeederrtsp.h iptv/iptvfeederudp.h - HEADERS += iptv/iptvfeederfile.h iptv/iptvfeederlive.h - HEADERS += iptv/iptvfeederrtp.h iptv/timeoutedtaskscheduler.h - - SOURCES += iptvchannel.cpp iptvrecorder.cpp - SOURCES += iptvsignalmonitor.cpp - SOURCES += iptv/iptvchannelfetcher.cpp - SOURCES += iptv/iptvmediasink.cpp - SOURCES += iptv/iptvfeeder.cpp iptv/iptvfeederwrapper.cpp - SOURCES += iptv/iptvfeederrtsp.cpp iptv/iptvfeederudp.cpp - SOURCES += iptv/iptvfeederfile.cpp iptv/iptvfeederlive.cpp - SOURCES += iptv/iptvfeederrtp.cpp iptv/timeoutedtaskscheduler.cpp - - DEFINES += USING_IPTV - } + # Support for RTP/UDP streams + HEADERS += iptvchannel.h iptvrecorder.h + HEADERS += iptvsignalmonitor.h + + SOURCES += iptvchannel.cpp iptvrecorder.cpp + SOURCES += iptvsignalmonitor.cpp # Support for HDHomeRun box using_hdhomerun { diff --git a/mythtv/libs/libmythtv/iptv/README.RTSP b/mythtv/libs/libmythtv/rtp/README.RTSP similarity index 100% rename from mythtv/libs/libmythtv/iptv/README.RTSP rename to mythtv/libs/libmythtv/rtp/README.RTSP diff --git a/mythtv/libs/libmythtv/iptv/README.UDP b/mythtv/libs/libmythtv/rtp/README.UDP similarity index 100% rename from mythtv/libs/libmythtv/iptv/README.UDP rename to mythtv/libs/libmythtv/rtp/README.UDP diff --git a/mythtv/libs/libmythtv/rtp/rtpfixedheader.h b/mythtv/libs/libmythtv/rtp/rtpfixedheader.h new file mode 100644 index 00000000000..5c52092f881 --- /dev/null +++ b/mythtv/libs/libmythtv/rtp/rtpfixedheader.h @@ -0,0 +1,63 @@ +/* -*- Mode: c++ -*- + * Copyright (c) 2012 Digital Nirvana, Inc. + * Distributed as part of MythTV under GPL v2 and later. + */ + +/** \brief RTP Fixed Header for all packets. + * + * The RTP Header exists for all RTP packets, it contains a payload + * type, timestamp and a sequence number for packet reordering. + */ +class RTPFixedHeader +{ + public: + RTPFixedHeader(const char *data, uint sz) : + m_data(data) + { + // TODO verify packet is big enough to contain the data + m_valid = 2 == GetVersion(); + } + + bool IsValid(void) const { return m_valid; } + uint GetVersion(void) const { return (m_data[0] >> 6); } + uint GetExtension(void) const { return (m_data[0] >> 4) & 0x1; } + uint GetCSRCCount(void) const { return m_data[0] & 0xf; } + + enum { + kPayLoadTypePCMAudio = 8, + kPayLoadTypeMPEGAudio = 12, + kPayLoadTypeH261Video = 31, + kPayLoadTypeMPEG2Video = 32, + kPayLoadTypeTS = 33, + kPayLoadTypeH263Video = 34, + }; + + uint GetPayloadType(void) const + { + return m_data[1] & 0x7f; + } + + uint GetSequenceNumber(void) const + { + return 0; // TODO -- return data and ensure proper byte order. + } + + uint GetTimeStamp(void) const + { + return 0; // TODO -- return data and ensure proper byte order. + } + + uint GetSynchronizationSource(void) const + { + return 0; // TODO -- return data and ensure proper byte order. + } + + uint GetContributingSource(uint i) const + { + return 0; // TODO -- return data and ensure proper byte order. + } + + private: + unsigned char *m_data; + bool m_valid; +}; diff --git a/mythtv/libs/libmythtv/rtp/rtppacketbuffer.h b/mythtv/libs/libmythtv/rtp/rtppacketbuffer.h new file mode 100644 index 00000000000..dc807848cc2 --- /dev/null +++ b/mythtv/libs/libmythtv/rtp/rtppacketbuffer.h @@ -0,0 +1,26 @@ +/* -*- Mode: c++ -*- + * RTPPacketBuffer + * Copyright (c) 2012 Digital Nirvana, Inc. + * Distributed as part of MythTV under GPL v2 and later. + */ + +class RTPPacketBuffer +{ + RTPPacketBuffer(uint bitrate); + ~RTPPacketBuffer(); + + /// Adds RFC 3550 RTP data packet + void PushDataPacket(unsigned char *data, uint size); + + /// Adds SMPTE 2022 Forward Error Correction Stream packet + void PushFECPacket(unsigned char *data, uint size, int fec_stream_num); + + /// Returns number of re-ordered packets ready for reading + uint AvailablePackets(void) const; + + /// Fetches an RTP Data Packet for processing + RTPDataPacket *PopDataPacket(void); + + /// Frees an RTPDataPacket returned by PopDataPacket. + void FreeDataPacket(RTPDataPacket*); +}; diff --git a/mythtv/libs/libmythtv/scanwizard.cpp b/mythtv/libs/libmythtv/scanwizard.cpp index 4591f9268c1..63a83985eda 100644 --- a/mythtv/libs/libmythtv/scanwizard.cpp +++ b/mythtv/libs/libmythtv/scanwizard.cpp @@ -115,7 +115,9 @@ void ScanWizard::SetPage(const QString &pageTitle) else if (scantype == ScanTypeSetting::IPTVImport) { do_scan = false; - scannerPane->ImportM3U(cardid, inputname, sourceid); + LOG(VB_GENERAL, LOG_INFO, "M3U Import not implemented."); + // TODO FIXME re-implement.. + //scannerPane->ImportM3U(cardid, inputname, sourceid); } else if ((scantype == ScanTypeSetting::FullScan_ATSC) || (scantype == ScanTypeSetting::FullTransportScan) || diff --git a/mythtv/libs/libs.pro b/mythtv/libs/libs.pro index db027523c36..270cb98ad64 100644 --- a/mythtv/libs/libs.pro +++ b/mythtv/libs/libs.pro @@ -9,7 +9,6 @@ SUBDIRS += libmythbluray libmythfreesurround libmythbase SUBDIRS += libmythservicecontracts using_mheg:SUBDIRS += libmythfreemheg -using_live:SUBDIRS += libmythlivemedia using_hdhomerun:SUBDIRS += libmythhdhomerun using_x11:SUBDIRS += libmythnvctrl !contains( CONFIG_LIBMPEG2EXTERNAL, yes):SUBDIRS += libmythmpeg2