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