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// MPEG-4 audio, using LATM multiplexing
19// Implementation
20
21#include "MPEG4LATMAudioRTPSource.hh"
22
23////////// LATMBufferedPacket and LATMBufferedPacketFactory //////////
24
25class LATMBufferedPacket: public BufferedPacket {
26public:
27 LATMBufferedPacket(Boolean includeLATMDataLengthField);
28 virtual ~LATMBufferedPacket();
29
30private: // redefined virtual functions
31 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
32 unsigned dataSize);
33
34private:
35 Boolean fIncludeLATMDataLengthField;
36};
37
38class LATMBufferedPacketFactory: public BufferedPacketFactory {
39private: // redefined virtual functions
40 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
41};
42
43///////// MPEG4LATMAudioRTPSource implementation ////////
44
45MPEG4LATMAudioRTPSource*
46MPEG4LATMAudioRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
47 unsigned char rtpPayloadFormat,
48 unsigned rtpTimestampFrequency) {
49 return new MPEG4LATMAudioRTPSource(env, RTPgs, rtpPayloadFormat,
50 rtpTimestampFrequency);
51}
52
53MPEG4LATMAudioRTPSource
54::MPEG4LATMAudioRTPSource(UsageEnvironment& env, Groupsock* RTPgs,
55 unsigned char rtpPayloadFormat,
56 unsigned rtpTimestampFrequency)
57 : MultiFramedRTPSource(env, RTPgs,
58 rtpPayloadFormat, rtpTimestampFrequency,
59 new LATMBufferedPacketFactory),
60 fIncludeLATMDataLengthField(True) {
61}
62
63MPEG4LATMAudioRTPSource::~MPEG4LATMAudioRTPSource() {
64}
65
66void MPEG4LATMAudioRTPSource::omitLATMDataLengthField() {
67 fIncludeLATMDataLengthField = False;
68}
69
70Boolean MPEG4LATMAudioRTPSource
71::processSpecialHeader(BufferedPacket* packet,
72 unsigned& resultSpecialHeaderSize) {
73 fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame;
74 // whether the *previous* packet ended a frame
75
76 // The RTP "M" (marker) bit indicates the last fragment of a frame:
77 fCurrentPacketCompletesFrame = packet->rtpMarkerBit();
78
79 // There is no special header
80 resultSpecialHeaderSize = 0;
81 return True;
82}
83
84char const* MPEG4LATMAudioRTPSource::MIMEtype() const {
85 return "audio/MP4A-LATM";
86}
87
88
89////////// LATMBufferedPacket and LATMBufferedPacketFactory implementation
90
91LATMBufferedPacket::LATMBufferedPacket(Boolean includeLATMDataLengthField)
92 : fIncludeLATMDataLengthField(includeLATMDataLengthField) {
93}
94
95LATMBufferedPacket::~LATMBufferedPacket() {
96}
97
98unsigned LATMBufferedPacket
99::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) {
100 // Look at the LATM data length byte(s), to determine the size
101 // of the LATM payload.
102 unsigned resultFrameSize = 0;
103 unsigned i;
104 for (i = 0; i < dataSize; ++i) {
105 resultFrameSize += framePtr[i];
106 if (framePtr[i] != 0xFF) break;
107 }
108 ++i;
109 if (fIncludeLATMDataLengthField) {
110 resultFrameSize += i;
111 } else {
112 framePtr += i;
113 dataSize -= i;
114 }
115
116 return (resultFrameSize <= dataSize) ? resultFrameSize : dataSize;
117}
118
119BufferedPacket* LATMBufferedPacketFactory
120::createNewPacket(MultiFramedRTPSource* ourSource) {
121 MPEG4LATMAudioRTPSource* source = (MPEG4LATMAudioRTPSource*)ourSource;
122 return new LATMBufferedPacket(source->returnedFrameIncludesLATMDataLengthField());
123}
124
125
126////////// parseStreamMuxConfigStr() implementation //////////
127
128static Boolean getNibble(char const*& configStr,
129 unsigned char& resultNibble) {
130 char c = configStr[0];
131 if (c == '\0') return False; // we've reached the end
132
133 if (c >= '0' && c <= '9') {
134 resultNibble = c - '0';
135 } else if (c >= 'A' && c <= 'F') {
136 resultNibble = 10 + c - 'A';
137 } else if (c >= 'a' && c <= 'f') {
138 resultNibble = 10 + c - 'a';
139 } else {
140 return False;
141 }
142
143 ++configStr; // move to the next nibble
144 return True;
145}
146
147static Boolean getByte(char const*& configStr, unsigned char& resultByte) {
148 resultByte = 0; // by default, in case parsing fails
149
150 unsigned char firstNibble;
151 if (!getNibble(configStr, firstNibble)) return False;
152 resultByte = firstNibble<<4;
153
154 unsigned char secondNibble = 0;
155 if (!getNibble(configStr, secondNibble) && configStr[0] != '\0') {
156 // There's a second nibble, but it's malformed
157 return False;
158 }
159 resultByte |= secondNibble;
160
161 return True;
162}
163
164Boolean
165parseStreamMuxConfigStr(char const* configStr,
166 // result parameters:
167 Boolean& audioMuxVersion,
168 Boolean& allStreamsSameTimeFraming,
169 unsigned char& numSubFrames,
170 unsigned char& numProgram,
171 unsigned char& numLayer,
172 unsigned char*& audioSpecificConfig,
173 unsigned& audioSpecificConfigSize) {
174 // Set default versions of the result parameters:
175 audioMuxVersion = False;
176 allStreamsSameTimeFraming = True;
177 numSubFrames = numProgram = numLayer = 0;
178 audioSpecificConfig = NULL;
179 audioSpecificConfigSize = 0;
180
181 do {
182 if (configStr == NULL) break;
183
184 unsigned char nextByte;
185
186 if (!getByte(configStr, nextByte)) break;
187 audioMuxVersion = (nextByte&0x80) != 0;
188 if (audioMuxVersion) break;
189
190 allStreamsSameTimeFraming = ((nextByte&0x40)>>6) != 0;
191 numSubFrames = (nextByte&0x3F);
192
193 if (!getByte(configStr, nextByte)) break;
194 numProgram = (nextByte&0xF0)>>4;
195
196 numLayer = (nextByte&0x0E)>>1;
197
198 // The one remaining bit, and the rest of the string,
199 // are used for "audioSpecificConfig":
200 unsigned char remainingBit = nextByte&1;
201
202 unsigned ascSize = (strlen(configStr)+1)/2 + 1;
203 audioSpecificConfig = new unsigned char[ascSize];
204
205 Boolean parseSuccess;
206 unsigned i = 0;
207 do {
208 nextByte = 0;
209 parseSuccess = getByte(configStr, nextByte);
210 audioSpecificConfig[i++] = (remainingBit<<7)|((nextByte&0xFE)>>1);
211 remainingBit = nextByte&1;
212 } while (parseSuccess);
213 if (i != ascSize) break; // part of the remaining string was bad
214
215 audioSpecificConfigSize = ascSize;
216 return True; // parsing succeeded
217 } while (0);
218
219 delete[] audioSpecificConfig;
220 return False; // parsing failed
221}
222
223unsigned char* parseStreamMuxConfigStr(char const* configStr,
224 // result parameter:
225 unsigned& audioSpecificConfigSize) {
226 Boolean audioMuxVersion, allStreamsSameTimeFraming;
227 unsigned char numSubFrames, numProgram, numLayer;
228 unsigned char* audioSpecificConfig;
229
230 if (!parseStreamMuxConfigStr(configStr,
231 audioMuxVersion, allStreamsSameTimeFraming,
232 numSubFrames, numProgram, numLayer,
233 audioSpecificConfig, audioSpecificConfigSize)) {
234 audioSpecificConfigSize = 0;
235 return NULL;
236 }
237
238 return audioSpecificConfig;
239}
240
241unsigned char* parseGeneralConfigStr(char const* configStr,
242 // result parameter:
243 unsigned& configSize) {
244 unsigned char* config = NULL;
245 do {
246 if (configStr == NULL) break;
247 configSize = (strlen(configStr)+1)/2;
248
249 config = new unsigned char[configSize];
250 if (config == NULL) break;
251
252 unsigned i;
253 for (i = 0; i < configSize; ++i) {
254 if (!getByte(configStr, config[i])) break;
255 }
256 if (i != configSize) break; // part of the string was bad
257
258 return config;
259 } while (0);
260
261 configSize = 0;
262 delete[] config;
263 return NULL;
264}
265