| 1 | /********** |
| 2 | This library is free software; you can redistribute it and/or modify it under |
| 3 | the terms of the GNU Lesser General Public License as published by the |
| 4 | Free Software Foundation; either version 3 of the License, or (at your |
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
| 6 | |
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT |
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
| 10 | more details. |
| 11 | |
| 12 | You should have received a copy of the GNU Lesser General Public License |
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., |
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 15 | **********/ |
| 16 | // "liveMedia" |
| 17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
| 18 | // MPEG4-GENERIC ("audio", "video", or "application") RTP stream sources |
| 19 | // Implementation |
| 20 | |
| 21 | #include "MPEG4GenericRTPSource.hh" |
| 22 | #include "BitVector.hh" |
| 23 | #include "MPEG4LATMAudioRTPSource.hh" // for parseGeneralConfigStr() |
| 24 | |
| 25 | ////////// MPEG4GenericBufferedPacket and MPEG4GenericBufferedPacketFactory |
| 26 | |
| 27 | class MPEG4GenericBufferedPacket: public BufferedPacket { |
| 28 | public: |
| 29 | MPEG4GenericBufferedPacket(MPEG4GenericRTPSource* ourSource); |
| 30 | virtual ~MPEG4GenericBufferedPacket(); |
| 31 | |
| 32 | private: // redefined virtual functions |
| 33 | virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, |
| 34 | unsigned dataSize); |
| 35 | private: |
| 36 | MPEG4GenericRTPSource* fOurSource; |
| 37 | }; |
| 38 | |
| 39 | class MPEG4GenericBufferedPacketFactory: public BufferedPacketFactory { |
| 40 | private: // redefined virtual functions |
| 41 | virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); |
| 42 | }; |
| 43 | |
| 44 | |
| 45 | ////////// AUHeader ////////// |
| 46 | struct { |
| 47 | unsigned ; |
| 48 | unsigned ; // indexDelta for the 2nd & subsequent headers |
| 49 | }; |
| 50 | |
| 51 | |
| 52 | ///////// MPEG4GenericRTPSource implementation //////// |
| 53 | |
| 54 | //##### NOTE: INCOMPLETE!!! Support more modes, and interleaving ##### |
| 55 | |
| 56 | MPEG4GenericRTPSource* |
| 57 | MPEG4GenericRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, |
| 58 | unsigned char rtpPayloadFormat, |
| 59 | unsigned rtpTimestampFrequency, |
| 60 | char const* mediumName, |
| 61 | char const* mode, |
| 62 | unsigned sizeLength, unsigned indexLength, |
| 63 | unsigned indexDeltaLength |
| 64 | ) { |
| 65 | return new MPEG4GenericRTPSource(env, RTPgs, rtpPayloadFormat, |
| 66 | rtpTimestampFrequency, mediumName, |
| 67 | mode, sizeLength, indexLength, |
| 68 | indexDeltaLength |
| 69 | ); |
| 70 | } |
| 71 | |
| 72 | MPEG4GenericRTPSource |
| 73 | ::MPEG4GenericRTPSource(UsageEnvironment& env, Groupsock* RTPgs, |
| 74 | unsigned char rtpPayloadFormat, |
| 75 | unsigned rtpTimestampFrequency, |
| 76 | char const* mediumName, |
| 77 | char const* mode, |
| 78 | unsigned sizeLength, unsigned indexLength, |
| 79 | unsigned indexDeltaLength |
| 80 | ) |
| 81 | : MultiFramedRTPSource(env, RTPgs, |
| 82 | rtpPayloadFormat, rtpTimestampFrequency, |
| 83 | new MPEG4GenericBufferedPacketFactory), |
| 84 | fSizeLength(sizeLength), fIndexLength(indexLength), |
| 85 | fIndexDeltaLength(indexDeltaLength), |
| 86 | fNumAUHeaders(0), fNextAUHeader(0), fAUHeaders(NULL) { |
| 87 | unsigned mimeTypeLength = |
| 88 | strlen(mediumName) + 14 /* strlen("/MPEG4-GENERIC") */ + 1; |
| 89 | fMIMEType = new char[mimeTypeLength]; |
| 90 | if (fMIMEType != NULL) { |
| 91 | sprintf(fMIMEType, "%s/MPEG4-GENERIC" , mediumName); |
| 92 | } |
| 93 | |
| 94 | fMode = strDup(mode); |
| 95 | // Check for a "mode" that we don't yet support: //##### |
| 96 | if (mode == NULL || |
| 97 | (strcmp(mode, "aac-hbr" ) != 0 && strcmp(mode, "generic" ) != 0)) { |
| 98 | envir() << "MPEG4GenericRTPSource Warning: Unknown or unsupported \"mode\": " |
| 99 | << mode << "\n" ; |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | MPEG4GenericRTPSource::~MPEG4GenericRTPSource() { |
| 104 | delete[] fAUHeaders; |
| 105 | delete[] fMode; |
| 106 | delete[] fMIMEType; |
| 107 | } |
| 108 | |
| 109 | Boolean MPEG4GenericRTPSource |
| 110 | ::(BufferedPacket* packet, |
| 111 | unsigned& ) { |
| 112 | unsigned char* = packet->data(); |
| 113 | unsigned packetSize = packet->dataSize(); |
| 114 | |
| 115 | fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame; |
| 116 | // whether the *previous* packet ended a frame |
| 117 | |
| 118 | // The RTP "M" (marker) bit indicates the last fragment of a frame: |
| 119 | fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); |
| 120 | |
| 121 | // default values: |
| 122 | resultSpecialHeaderSize = 0; |
| 123 | fNumAUHeaders = 0; |
| 124 | fNextAUHeader = 0; |
| 125 | delete[] fAUHeaders; fAUHeaders = NULL; |
| 126 | |
| 127 | if (fSizeLength > 0) { |
| 128 | // The packet begins with a "AU Header Section". Parse it, to |
| 129 | // determine the "AU-header"s for each frame present in this packet: |
| 130 | resultSpecialHeaderSize += 2; |
| 131 | if (packetSize < resultSpecialHeaderSize) return False; |
| 132 | |
| 133 | unsigned = (headerStart[0]<<8)|headerStart[1]; |
| 134 | unsigned = (AU_headers_length+7)/8; |
| 135 | if (packetSize |
| 136 | < resultSpecialHeaderSize + AU_headers_length_bytes) return False; |
| 137 | resultSpecialHeaderSize += AU_headers_length_bytes; |
| 138 | |
| 139 | // Figure out how many AU-headers are present in the packet: |
| 140 | int bitsAvail = AU_headers_length - (fSizeLength + fIndexLength); |
| 141 | if (bitsAvail >= 0 && (fSizeLength + fIndexDeltaLength) > 0) { |
| 142 | fNumAUHeaders = 1 + bitsAvail/(fSizeLength + fIndexDeltaLength); |
| 143 | } |
| 144 | if (fNumAUHeaders > 0) { |
| 145 | fAUHeaders = new AUHeader[fNumAUHeaders]; |
| 146 | // Fill in each header: |
| 147 | BitVector bv(&headerStart[2], 0, AU_headers_length); |
| 148 | fAUHeaders[0].size = bv.getBits(fSizeLength); |
| 149 | fAUHeaders[0].index = bv.getBits(fIndexLength); |
| 150 | |
| 151 | for (unsigned i = 1; i < fNumAUHeaders; ++i) { |
| 152 | fAUHeaders[i].size = bv.getBits(fSizeLength); |
| 153 | fAUHeaders[i].index = bv.getBits(fIndexDeltaLength); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | } |
| 158 | |
| 159 | return True; |
| 160 | } |
| 161 | |
| 162 | char const* MPEG4GenericRTPSource::MIMEtype() const { |
| 163 | return fMIMEType; |
| 164 | } |
| 165 | |
| 166 | |
| 167 | ////////// MPEG4GenericBufferedPacket |
| 168 | ////////// and MPEG4GenericBufferedPacketFactory implementation |
| 169 | |
| 170 | MPEG4GenericBufferedPacket |
| 171 | ::MPEG4GenericBufferedPacket(MPEG4GenericRTPSource* ourSource) |
| 172 | : fOurSource(ourSource) { |
| 173 | } |
| 174 | |
| 175 | MPEG4GenericBufferedPacket::~MPEG4GenericBufferedPacket() { |
| 176 | } |
| 177 | |
| 178 | unsigned MPEG4GenericBufferedPacket |
| 179 | ::nextEnclosedFrameSize(unsigned char*& /*framePtr*/, unsigned dataSize) { |
| 180 | // WE CURRENTLY DON'T IMPLEMENT INTERLEAVING. FIX THIS! ##### |
| 181 | AUHeader* = fOurSource->fAUHeaders; |
| 182 | if (auHeader == NULL) return dataSize; |
| 183 | unsigned = fOurSource->fNumAUHeaders; |
| 184 | |
| 185 | if (fOurSource->fNextAUHeader >= numAUHeaders) { |
| 186 | fOurSource->envir() << "MPEG4GenericBufferedPacket::nextEnclosedFrameSize(" |
| 187 | << dataSize << "): data error (" |
| 188 | << auHeader << "," << fOurSource->fNextAUHeader |
| 189 | << "," << numAUHeaders << ")!\n" ; |
| 190 | return dataSize; |
| 191 | } |
| 192 | |
| 193 | auHeader = &auHeader[fOurSource->fNextAUHeader++]; |
| 194 | return auHeader->size <= dataSize ? auHeader->size : dataSize; |
| 195 | } |
| 196 | |
| 197 | BufferedPacket* MPEG4GenericBufferedPacketFactory |
| 198 | ::createNewPacket(MultiFramedRTPSource* ourSource) { |
| 199 | return new MPEG4GenericBufferedPacket((MPEG4GenericRTPSource*)ourSource); |
| 200 | } |
| 201 | |
| 202 | |
| 203 | ////////// samplingFrequencyFromAudioSpecificConfig() implementation ////////// |
| 204 | |
| 205 | static unsigned const samplingFrequencyFromIndex[16] = { |
| 206 | 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, |
| 207 | 16000, 12000, 11025, 8000, 7350, 0, 0, 0 |
| 208 | }; |
| 209 | |
| 210 | unsigned samplingFrequencyFromAudioSpecificConfig(char const* configStr) { |
| 211 | unsigned char* config = NULL; |
| 212 | unsigned result = 0; // if returned, indicates an error |
| 213 | |
| 214 | do { |
| 215 | // Begin by parsing the config string: |
| 216 | unsigned configSize; |
| 217 | config = parseGeneralConfigStr(configStr, configSize); |
| 218 | if (config == NULL) break; |
| 219 | |
| 220 | if (configSize < 2) break; |
| 221 | unsigned char samplingFrequencyIndex = ((config[0]&0x07)<<1) | (config[1]>>7); |
| 222 | if (samplingFrequencyIndex < 15) { |
| 223 | result = samplingFrequencyFromIndex[samplingFrequencyIndex]; |
| 224 | break; |
| 225 | } |
| 226 | |
| 227 | // Index == 15 means that the actual frequency is next (24 bits): |
| 228 | if (configSize < 5) break; |
| 229 | result = ((config[1]&0x7F)<<17) | (config[2]<<9) | (config[3]<<1) | (config[4]>>7); |
| 230 | } while (0); |
| 231 | |
| 232 | delete[] config; |
| 233 | return result; |
| 234 | } |
| 235 | |