1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 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
27class MPEG4GenericBufferedPacket: public BufferedPacket {
28public:
29 MPEG4GenericBufferedPacket(MPEG4GenericRTPSource* ourSource);
30 virtual ~MPEG4GenericBufferedPacket();
31
32private: // redefined virtual functions
33 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
34 unsigned dataSize);
35private:
36 MPEG4GenericRTPSource* fOurSource;
37};
38
39class MPEG4GenericBufferedPacketFactory: public BufferedPacketFactory {
40private: // redefined virtual functions
41 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
42};
43
44
45////////// AUHeader //////////
46struct AUHeader {
47 unsigned size;
48 unsigned index; // indexDelta for the 2nd & subsequent headers
49};
50
51
52///////// MPEG4GenericRTPSource implementation ////////
53
54//##### NOTE: INCOMPLETE!!! Support more modes, and interleaving #####
55
56MPEG4GenericRTPSource*
57MPEG4GenericRTPSource::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
72MPEG4GenericRTPSource
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
103MPEG4GenericRTPSource::~MPEG4GenericRTPSource() {
104 delete[] fAUHeaders;
105 delete[] fMode;
106 delete[] fMIMEType;
107}
108
109Boolean MPEG4GenericRTPSource
110::processSpecialHeader(BufferedPacket* packet,
111 unsigned& resultSpecialHeaderSize) {
112 unsigned char* headerStart = 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 AU_headers_length = (headerStart[0]<<8)|headerStart[1];
134 unsigned AU_headers_length_bytes = (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
162char const* MPEG4GenericRTPSource::MIMEtype() const {
163 return fMIMEType;
164}
165
166
167////////// MPEG4GenericBufferedPacket
168////////// and MPEG4GenericBufferedPacketFactory implementation
169
170MPEG4GenericBufferedPacket
171::MPEG4GenericBufferedPacket(MPEG4GenericRTPSource* ourSource)
172 : fOurSource(ourSource) {
173}
174
175MPEG4GenericBufferedPacket::~MPEG4GenericBufferedPacket() {
176}
177
178unsigned MPEG4GenericBufferedPacket
179::nextEnclosedFrameSize(unsigned char*& /*framePtr*/, unsigned dataSize) {
180 // WE CURRENTLY DON'T IMPLEMENT INTERLEAVING. FIX THIS! #####
181 AUHeader* auHeader = fOurSource->fAUHeaders;
182 if (auHeader == NULL) return dataSize;
183 unsigned numAUHeaders = 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
197BufferedPacket* MPEG4GenericBufferedPacketFactory
198::createNewPacket(MultiFramedRTPSource* ourSource) {
199 return new MPEG4GenericBufferedPacket((MPEG4GenericRTPSource*)ourSource);
200}
201
202
203////////// samplingFrequencyFromAudioSpecificConfig() implementation //////////
204
205static unsigned const samplingFrequencyFromIndex[16] = {
206 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
207 16000, 12000, 11025, 8000, 7350, 0, 0, 0
208};
209
210unsigned 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