/********** This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. (See .) This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA **********/ // "liveMedia" // Copyright (c) 1996-2020 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 const 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; }