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// JPEG Video (RFC 2435) RTP Sources
19// Implementation
20
21#include "JPEGVideoRTPSource.hh"
22
23////////// JPEGBufferedPacket and JPEGBufferedPacketFactory //////////
24
25class JPEGBufferedPacket: public BufferedPacket {
26public:
27 Boolean completesFrame;
28
29private:
30 // Redefined virtual functions:
31 virtual void reset();
32 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
33 unsigned dataSize);
34};
35
36class JPEGBufferedPacketFactory: public BufferedPacketFactory {
37private: // redefined virtual functions
38 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
39};
40
41
42////////// JPEGVideoRTPSource implementation //////////
43
44#define BYTE unsigned char
45#define WORD unsigned
46#define DWORD unsigned long
47
48JPEGVideoRTPSource*
49JPEGVideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
50 unsigned char rtpPayloadFormat,
51 unsigned rtpTimestampFrequency,
52 unsigned defaultWidth, unsigned defaultHeight) {
53 return new JPEGVideoRTPSource(env, RTPgs, rtpPayloadFormat,
54 rtpTimestampFrequency, defaultWidth, defaultHeight);
55}
56
57JPEGVideoRTPSource::JPEGVideoRTPSource(UsageEnvironment& env,
58 Groupsock* RTPgs,
59 unsigned char rtpPayloadFormat,
60 unsigned rtpTimestampFrequency,
61 unsigned defaultWidth, unsigned defaultHeight)
62 : MultiFramedRTPSource(env, RTPgs,
63 rtpPayloadFormat, rtpTimestampFrequency,
64 new JPEGBufferedPacketFactory),
65 fDefaultWidth(defaultWidth), fDefaultHeight(defaultHeight) {
66}
67
68JPEGVideoRTPSource::~JPEGVideoRTPSource() {
69}
70
71enum {
72 MARKER_SOF0 = 0xc0, // start-of-frame, baseline scan
73 MARKER_SOI = 0xd8, // start of image
74 MARKER_EOI = 0xd9, // end of image
75 MARKER_SOS = 0xda, // start of scan
76 MARKER_DRI = 0xdd, // restart interval
77 MARKER_DQT = 0xdb, // define quantization tables
78 MARKER_DHT = 0xc4, // huffman tables
79 MARKER_APP_FIRST = 0xe0,
80 MARKER_APP_LAST = 0xef,
81 MARKER_COMMENT = 0xfe,
82};
83
84static unsigned char const lum_dc_codelens[] = {
85 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
86};
87
88static unsigned char const lum_dc_symbols[] = {
89 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
90};
91
92static unsigned char const lum_ac_codelens[] = {
93 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d,
94};
95
96static unsigned char const lum_ac_symbols[] = {
97 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
98 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
99 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
100 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
101 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
102 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
103 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
104 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
105 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
106 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
107 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
108 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
109 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
110 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
111 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
112 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
113 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
114 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
115 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
116 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
117 0xf9, 0xfa,
118};
119
120static unsigned char const chm_dc_codelens[] = {
121 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
122};
123
124static unsigned char const chm_dc_symbols[] = {
125 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
126};
127
128static unsigned char const chm_ac_codelens[] = {
129 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77,
130};
131
132static unsigned char const chm_ac_symbols[] = {
133 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
134 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
135 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
136 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
137 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
138 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
139 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
140 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
141 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
142 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
143 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
144 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
145 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
146 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
147 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
148 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
149 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
150 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
151 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
152 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
153 0xf9, 0xfa,
154};
155
156static void createHuffmanHeader(unsigned char*& p,
157 unsigned char const* codelens,
158 int ncodes,
159 unsigned char const* symbols,
160 int nsymbols,
161 int tableNo, int tableClass) {
162 *p++ = 0xff; *p++ = MARKER_DHT;
163 *p++ = 0; /* length msb */
164 *p++ = 3 + ncodes + nsymbols; /* length lsb */
165 *p++ = (tableClass << 4) | tableNo;
166 memcpy(p, codelens, ncodes);
167 p += ncodes;
168 memcpy(p, symbols, nsymbols);
169 p += nsymbols;
170}
171
172static unsigned computeJPEGHeaderSize(unsigned qtlen, unsigned dri) {
173 unsigned qtlen_half = qtlen/2; // in case qtlen is odd; shouldn't happen
174 qtlen = qtlen_half*2;
175
176 unsigned numQtables = qtlen > 64 ? 2 : 1;
177 return 485 + numQtables*5 + qtlen + (dri > 0 ? 6 : 0);
178}
179
180static void createJPEGHeader(unsigned char* buf, unsigned type,
181 unsigned w, unsigned h,
182 unsigned char const* qtables, unsigned qtlen,
183 unsigned dri) {
184 unsigned char *ptr = buf;
185 unsigned numQtables = qtlen > 64 ? 2 : 1;
186
187 // MARKER_SOI:
188 *ptr++ = 0xFF; *ptr++ = MARKER_SOI;
189
190 // MARKER_APP_FIRST:
191 *ptr++ = 0xFF; *ptr++ = MARKER_APP_FIRST;
192 *ptr++ = 0x00; *ptr++ = 0x10; // size of chunk
193 *ptr++ = 'J'; *ptr++ = 'F'; *ptr++ = 'I'; *ptr++ = 'F'; *ptr++ = 0x00;
194 *ptr++ = 0x01; *ptr++ = 0x01; // JFIF format version (1.1)
195 *ptr++ = 0x00; // no units
196 *ptr++ = 0x00; *ptr++ = 0x01; // Horizontal pixel aspect ratio
197 *ptr++ = 0x00; *ptr++ = 0x01; // Vertical pixel aspect ratio
198 *ptr++ = 0x00; *ptr++ = 0x00; // no thumbnail
199
200 // MARKER_DRI:
201 if (dri > 0) {
202 *ptr++ = 0xFF; *ptr++ = MARKER_DRI;
203 *ptr++ = 0x00; *ptr++ = 0x04; // size of chunk
204 *ptr++ = (BYTE)(dri >> 8); *ptr++ = (BYTE)(dri); // restart interval
205 }
206
207 // MARKER_DQT (luma):
208 unsigned tableSize = numQtables == 1 ? qtlen : qtlen/2;
209 *ptr++ = 0xFF; *ptr++ = MARKER_DQT;
210 *ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk
211 *ptr++ = 0x00; // precision(0), table id(0)
212 memcpy(ptr, qtables, tableSize);
213 qtables += tableSize;
214 ptr += tableSize;
215
216 if (numQtables > 1) {
217 unsigned tableSize = qtlen - qtlen/2;
218 // MARKER_DQT (chroma):
219 *ptr++ = 0xFF; *ptr++ = MARKER_DQT;
220 *ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk
221 *ptr++ = 0x01; // precision(0), table id(1)
222 memcpy(ptr, qtables, tableSize);
223 qtables += tableSize;
224 ptr += tableSize;
225 }
226
227 // MARKER_SOF0:
228 *ptr++ = 0xFF; *ptr++ = MARKER_SOF0;
229 *ptr++ = 0x00; *ptr++ = 0x11; // size of chunk
230 *ptr++ = 0x08; // sample precision
231 *ptr++ = (BYTE)(h >> 8);
232 *ptr++ = (BYTE)(h); // number of lines (must be a multiple of 8)
233 *ptr++ = (BYTE)(w >> 8);
234 *ptr++ = (BYTE)(w); // number of columns (must be a multiple of 8)
235 *ptr++ = 0x03; // number of components
236 *ptr++ = 0x01; // id of component
237 *ptr++ = type ? 0x22 : 0x21; // sampling ratio (h,v)
238 *ptr++ = 0x00; // quant table id
239 *ptr++ = 0x02; // id of component
240 *ptr++ = 0x11; // sampling ratio (h,v)
241 *ptr++ = numQtables == 1 ? 0x00 : 0x01; // quant table id
242 *ptr++ = 0x03; // id of component
243 *ptr++ = 0x11; // sampling ratio (h,v)
244 *ptr++ = numQtables == 1 ? 0x00 : 0x01; // quant table id
245
246 createHuffmanHeader(ptr, lum_dc_codelens, sizeof lum_dc_codelens,
247 lum_dc_symbols, sizeof lum_dc_symbols, 0, 0);
248 createHuffmanHeader(ptr, lum_ac_codelens, sizeof lum_ac_codelens,
249 lum_ac_symbols, sizeof lum_ac_symbols, 0, 1);
250 createHuffmanHeader(ptr, chm_dc_codelens, sizeof chm_dc_codelens,
251 chm_dc_symbols, sizeof chm_dc_symbols, 1, 0);
252 createHuffmanHeader(ptr, chm_ac_codelens, sizeof chm_ac_codelens,
253 chm_ac_symbols, sizeof chm_ac_symbols, 1, 1);
254
255 // MARKER_SOS:
256 *ptr++ = 0xFF; *ptr++ = MARKER_SOS;
257 *ptr++ = 0x00; *ptr++ = 0x0C; // size of chunk
258 *ptr++ = 0x03; // number of components
259 *ptr++ = 0x01; // id of component
260 *ptr++ = 0x00; // huffman table id (DC, AC)
261 *ptr++ = 0x02; // id of component
262 *ptr++ = 0x11; // huffman table id (DC, AC)
263 *ptr++ = 0x03; // id of component
264 *ptr++ = 0x11; // huffman table id (DC, AC)
265 *ptr++ = 0x00; // start of spectral
266 *ptr++ = 0x3F; // end of spectral
267 *ptr++ = 0x00; // successive approximation bit position (high, low)
268}
269
270// The default 'luma' and 'chroma' quantizer tables, in zigzag order:
271static unsigned char const defaultQuantizers[128] = {
272 // luma table:
273 16, 11, 12, 14, 12, 10, 16, 14,
274 13, 14, 18, 17, 16, 19, 24, 40,
275 26, 24, 22, 22, 24, 49, 35, 37,
276 29, 40, 58, 51, 61, 60, 57, 51,
277 56, 55, 64, 72, 92, 78, 64, 68,
278 87, 69, 55, 56, 80, 109, 81, 87,
279 95, 98, 103, 104, 103, 62, 77, 113,
280 121, 112, 100, 120, 92, 101, 103, 99,
281 // chroma table:
282 17, 18, 18, 24, 21, 24, 47, 26,
283 26, 47, 99, 66, 56, 66, 99, 99,
284 99, 99, 99, 99, 99, 99, 99, 99,
285 99, 99, 99, 99, 99, 99, 99, 99,
286 99, 99, 99, 99, 99, 99, 99, 99,
287 99, 99, 99, 99, 99, 99, 99, 99,
288 99, 99, 99, 99, 99, 99, 99, 99,
289 99, 99, 99, 99, 99, 99, 99, 99
290};
291
292static void makeDefaultQtables(unsigned char* resultTables, unsigned Q) {
293 int factor = Q;
294 int q;
295
296 if (Q < 1) factor = 1;
297 else if (Q > 99) factor = 99;
298
299 if (Q < 50) {
300 q = 5000 / factor;
301 } else {
302 q = 200 - factor*2;
303 }
304
305 for (int i = 0; i < 128; ++i) {
306 int newVal = (defaultQuantizers[i]*q + 50)/100;
307 if (newVal < 1) newVal = 1;
308 else if (newVal > 255) newVal = 255;
309 resultTables[i] = newVal;
310 }
311}
312
313Boolean JPEGVideoRTPSource
314::processSpecialHeader(BufferedPacket* packet,
315 unsigned& resultSpecialHeaderSize) {
316 unsigned char* headerStart = packet->data();
317 unsigned packetSize = packet->dataSize();
318
319 unsigned char* qtables = NULL;
320 unsigned qtlen = 0;
321 unsigned dri = 0;
322
323 // There's at least 8-byte video-specific header
324 /*
3250 1 2 3
3260 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
327+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328| Type-specific | Fragment Offset |
329+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
330| Type | Q | Width | Height |
331+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
332 */
333 if (packetSize < 8) return False;
334
335 resultSpecialHeaderSize = 8;
336
337 unsigned Offset = (unsigned)((DWORD)headerStart[1] << 16 | (DWORD)headerStart[2] << 8 | (DWORD)headerStart[3]);
338 unsigned Type = (unsigned)headerStart[4];
339 unsigned type = Type & 1;
340 unsigned Q = (unsigned)headerStart[5];
341 unsigned width = (unsigned)headerStart[6] * 8;
342 unsigned height = (unsigned)headerStart[7] * 8;
343 if ((width == 0 || height == 0) && fDefaultWidth != 0 && fDefaultHeight != 0) {
344 // Use the default width and height parameters instead:
345 width = fDefaultWidth;
346 height = fDefaultHeight;
347 }
348 if (width == 0) width = 256*8; // special case
349 if (height == 0) height = 256*8; // special case
350
351 if (Type > 63) {
352 // Restart Marker header present
353 /*
3540 1 2 3
3550 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
356+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
357| Restart Interval |F|L| Restart Count |
358+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
359 */
360 if (packetSize < resultSpecialHeaderSize + 4) return False;
361
362 unsigned RestartInterval = (unsigned)((WORD)headerStart[resultSpecialHeaderSize] << 8 | (WORD)headerStart[resultSpecialHeaderSize + 1]);
363 dri = RestartInterval;
364 resultSpecialHeaderSize += 4;
365 }
366
367 if (Offset == 0) {
368 if (Q > 127) {
369 // Quantization Table header present
370/*
3710 1 2 3
3720 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
373+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374| MBZ | Precision | Length |
375+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376| Quantization Table Data |
377| ... |
378+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379*/
380 if (packetSize < resultSpecialHeaderSize + 4) return False;
381
382 unsigned MBZ = (unsigned)headerStart[resultSpecialHeaderSize];
383 if (MBZ == 0) {
384 // unsigned Precision = (unsigned)headerStart[resultSpecialHeaderSize + 1];
385 unsigned Length = (unsigned)((WORD)headerStart[resultSpecialHeaderSize + 2] << 8 | (WORD)headerStart[resultSpecialHeaderSize + 3]);
386
387 //ASSERT(Length == 128);
388
389 resultSpecialHeaderSize += 4;
390
391 if (packetSize < resultSpecialHeaderSize + Length) return False;
392
393 qtlen = Length;
394 qtables = &headerStart[resultSpecialHeaderSize];
395
396 resultSpecialHeaderSize += Length;
397 }
398 }
399 }
400
401 // If this is the first (or only) fragment of a JPEG frame, then we need
402 // to synthesize a JPEG header, and prepend it to the incoming data.
403 // Hack: We can do this because we allowed space for it in
404 // our special "JPEGBufferedPacket" subclass. We also adjust
405 // "resultSpecialHeaderSize" to compensate for this, by subtracting
406 // the size of the synthesized header. Note that this will cause
407 // "resultSpecialHeaderSize" to become negative, but the code that called
408 // us (in "MultiFramedRTPSource") will handle this properly.
409 if (Offset == 0) {
410 unsigned char newQtables[128];
411 if (qtlen == 0) {
412 // A quantization table was not present in the RTP JPEG header,
413 // so use the default tables, scaled according to the "Q" factor:
414 makeDefaultQtables(newQtables, Q);
415 qtables = newQtables;
416 qtlen = sizeof newQtables;
417 }
418
419 unsigned hdrlen = computeJPEGHeaderSize(qtlen, dri);
420 resultSpecialHeaderSize -= hdrlen; // goes negative
421 headerStart += (int)resultSpecialHeaderSize; // goes backward
422 createJPEGHeader(headerStart, type, width, height, qtables, qtlen, dri);
423 }
424
425 fCurrentPacketBeginsFrame = (Offset == 0);
426
427 // The RTP "M" (marker) bit indicates the last fragment of a frame:
428 ((JPEGBufferedPacket*)packet)->completesFrame
429 = fCurrentPacketCompletesFrame = packet->rtpMarkerBit();
430
431 return True;
432}
433
434char const* JPEGVideoRTPSource::MIMEtype() const {
435 return "video/JPEG";
436}
437
438////////// JPEGBufferedPacket and JPEGBufferedPacketFactory implementation
439
440void JPEGBufferedPacket::reset() {
441 BufferedPacket::reset();
442
443 // Move our "fHead" and "fTail" forward, to allow space for a synthesized
444 // JPEG header to precede the RTP data that comes in over the network.
445 unsigned offset = MAX_JPEG_HEADER_SIZE;
446 if (offset > fPacketSize) offset = fPacketSize; // shouldn't happen
447 fHead = fTail = offset;
448}
449
450unsigned JPEGBufferedPacket
451::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) {
452 // Normally, the enclosed frame size is just "dataSize". If, however,
453 // the frame does not end with the "EOI" marker, then add this now:
454 if (completesFrame && dataSize >= 2 &&
455 !(framePtr[dataSize-2] == 0xFF && framePtr[dataSize-1] == MARKER_EOI)) {
456 framePtr[dataSize++] = 0xFF;
457 framePtr[dataSize++] = MARKER_EOI;
458 }
459 return dataSize;
460}
461
462BufferedPacket* JPEGBufferedPacketFactory
463::createNewPacket(MultiFramedRTPSource* /*ourSource*/) {
464 return new JPEGBufferedPacket;
465}
466