00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "JPEGVideoRTPSource.hh"
00022
00024
00025 class JPEGBufferedPacket: public BufferedPacket {
00026 public:
00027 Boolean completesFrame;
00028
00029 private:
00030
00031 virtual void reset();
00032 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
00033 unsigned dataSize);
00034 };
00035
00036 class JPEGBufferedPacketFactory: public BufferedPacketFactory {
00037 private:
00038 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
00039 };
00040
00041
00043
00044 #define BYTE unsigned char
00045 #define WORD unsigned
00046 #define DWORD unsigned long
00047
00048 JPEGVideoRTPSource*
00049 JPEGVideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
00050 unsigned char rtpPayloadFormat,
00051 unsigned rtpTimestampFrequency,
00052 unsigned defaultWidth, unsigned defaultHeight) {
00053 return new JPEGVideoRTPSource(env, RTPgs, rtpPayloadFormat,
00054 rtpTimestampFrequency, defaultWidth, defaultHeight);
00055 }
00056
00057 JPEGVideoRTPSource::JPEGVideoRTPSource(UsageEnvironment& env,
00058 Groupsock* RTPgs,
00059 unsigned char rtpPayloadFormat,
00060 unsigned rtpTimestampFrequency,
00061 unsigned defaultWidth, unsigned defaultHeight)
00062 : MultiFramedRTPSource(env, RTPgs,
00063 rtpPayloadFormat, rtpTimestampFrequency,
00064 new JPEGBufferedPacketFactory),
00065 fDefaultWidth(defaultWidth), fDefaultHeight(defaultHeight) {
00066 }
00067
00068 JPEGVideoRTPSource::~JPEGVideoRTPSource() {
00069 }
00070
00071 enum {
00072 MARKER_SOF0 = 0xc0,
00073 MARKER_SOI = 0xd8,
00074 MARKER_EOI = 0xd9,
00075 MARKER_SOS = 0xda,
00076 MARKER_DRI = 0xdd,
00077 MARKER_DQT = 0xdb,
00078 MARKER_DHT = 0xc4,
00079 MARKER_APP_FIRST = 0xe0,
00080 MARKER_APP_LAST = 0xef,
00081 MARKER_COMMENT = 0xfe,
00082 };
00083
00084 static unsigned char const lum_dc_codelens[] = {
00085 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
00086 };
00087
00088 static unsigned char const lum_dc_symbols[] = {
00089 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
00090 };
00091
00092 static unsigned char const lum_ac_codelens[] = {
00093 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d,
00094 };
00095
00096 static unsigned char const lum_ac_symbols[] = {
00097 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
00098 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
00099 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
00100 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
00101 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
00102 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
00103 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
00104 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
00105 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
00106 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
00107 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
00108 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
00109 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
00110 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
00111 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
00112 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
00113 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
00114 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
00115 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
00116 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
00117 0xf9, 0xfa,
00118 };
00119
00120 static unsigned char const chm_dc_codelens[] = {
00121 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
00122 };
00123
00124 static unsigned char const chm_dc_symbols[] = {
00125 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
00126 };
00127
00128 static unsigned char const chm_ac_codelens[] = {
00129 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77,
00130 };
00131
00132 static unsigned char const chm_ac_symbols[] = {
00133 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
00134 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
00135 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
00136 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
00137 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
00138 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
00139 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
00140 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
00141 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
00142 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
00143 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
00144 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
00145 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
00146 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
00147 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
00148 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
00149 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
00150 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
00151 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
00152 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
00153 0xf9, 0xfa,
00154 };
00155
00156 static void createHuffmanHeader(unsigned char*& p,
00157 unsigned char const* codelens,
00158 int ncodes,
00159 unsigned char const* symbols,
00160 int nsymbols,
00161 int tableNo, int tableClass) {
00162 *p++ = 0xff; *p++ = MARKER_DHT;
00163 *p++ = 0;
00164 *p++ = 3 + ncodes + nsymbols;
00165 *p++ = (tableClass << 4) | tableNo;
00166 memcpy(p, codelens, ncodes);
00167 p += ncodes;
00168 memcpy(p, symbols, nsymbols);
00169 p += nsymbols;
00170 }
00171
00172 static unsigned computeJPEGHeaderSize(unsigned qtlen, unsigned dri) {
00173 unsigned qtlen_half = qtlen/2;
00174 qtlen = qtlen_half*2;
00175
00176 unsigned numQtables = qtlen > 64 ? 2 : 1;
00177 return 485 + numQtables*5 + qtlen + (dri > 0 ? 6 : 0);
00178 }
00179
00180 static void createJPEGHeader(unsigned char* buf, unsigned type,
00181 unsigned w, unsigned h,
00182 unsigned char const* qtables, unsigned qtlen,
00183 unsigned dri) {
00184 unsigned char *ptr = buf;
00185 unsigned numQtables = qtlen > 64 ? 2 : 1;
00186
00187
00188 *ptr++ = 0xFF; *ptr++ = MARKER_SOI;
00189
00190
00191 *ptr++ = 0xFF; *ptr++ = MARKER_APP_FIRST;
00192 *ptr++ = 0x00; *ptr++ = 0x10;
00193 *ptr++ = 'J'; *ptr++ = 'F'; *ptr++ = 'I'; *ptr++ = 'F'; *ptr++ = 0x00;
00194 *ptr++ = 0x01; *ptr++ = 0x01;
00195 *ptr++ = 0x00;
00196 *ptr++ = 0x00; *ptr++ = 0x01;
00197 *ptr++ = 0x00; *ptr++ = 0x01;
00198 *ptr++ = 0x00; *ptr++ = 0x00;
00199
00200
00201 if (dri > 0) {
00202 *ptr++ = 0xFF; *ptr++ = MARKER_DRI;
00203 *ptr++ = 0x00; *ptr++ = 0x04;
00204 *ptr++ = (BYTE)(dri >> 8); *ptr++ = (BYTE)(dri);
00205 }
00206
00207
00208 unsigned tableSize = numQtables == 1 ? qtlen : qtlen/2;
00209 *ptr++ = 0xFF; *ptr++ = MARKER_DQT;
00210 *ptr++ = 0x00; *ptr++ = tableSize + 3;
00211 *ptr++ = 0x00;
00212 memcpy(ptr, qtables, tableSize);
00213 qtables += tableSize;
00214 ptr += tableSize;
00215
00216 if (numQtables > 1) {
00217 unsigned tableSize = qtlen - qtlen/2;
00218
00219 *ptr++ = 0xFF; *ptr++ = MARKER_DQT;
00220 *ptr++ = 0x00; *ptr++ = tableSize + 3;
00221 *ptr++ = 0x01;
00222 memcpy(ptr, qtables, tableSize);
00223 qtables += tableSize;
00224 ptr += tableSize;
00225 }
00226
00227
00228 *ptr++ = 0xFF; *ptr++ = MARKER_SOF0;
00229 *ptr++ = 0x00; *ptr++ = 0x11;
00230 *ptr++ = 0x08;
00231 *ptr++ = (BYTE)(h >> 8);
00232 *ptr++ = (BYTE)(h);
00233 *ptr++ = (BYTE)(w >> 8);
00234 *ptr++ = (BYTE)(w);
00235 *ptr++ = 0x03;
00236 *ptr++ = 0x01;
00237 *ptr++ = type ? 0x22 : 0x21;
00238 *ptr++ = 0x00;
00239 *ptr++ = 0x02;
00240 *ptr++ = 0x11;
00241 *ptr++ = numQtables == 1 ? 0x00 : 0x01;
00242 *ptr++ = 0x03;
00243 *ptr++ = 0x11;
00244 *ptr++ = numQtables == 1 ? 0x00 : 0x01;
00245
00246 createHuffmanHeader(ptr, lum_dc_codelens, sizeof lum_dc_codelens,
00247 lum_dc_symbols, sizeof lum_dc_symbols, 0, 0);
00248 createHuffmanHeader(ptr, lum_ac_codelens, sizeof lum_ac_codelens,
00249 lum_ac_symbols, sizeof lum_ac_symbols, 0, 1);
00250 createHuffmanHeader(ptr, chm_dc_codelens, sizeof chm_dc_codelens,
00251 chm_dc_symbols, sizeof chm_dc_symbols, 1, 0);
00252 createHuffmanHeader(ptr, chm_ac_codelens, sizeof chm_ac_codelens,
00253 chm_ac_symbols, sizeof chm_ac_symbols, 1, 1);
00254
00255
00256 *ptr++ = 0xFF; *ptr++ = MARKER_SOS;
00257 *ptr++ = 0x00; *ptr++ = 0x0C;
00258 *ptr++ = 0x03;
00259 *ptr++ = 0x01;
00260 *ptr++ = 0x00;
00261 *ptr++ = 0x02;
00262 *ptr++ = 0x11;
00263 *ptr++ = 0x03;
00264 *ptr++ = 0x11;
00265 *ptr++ = 0x00;
00266 *ptr++ = 0x3F;
00267 *ptr++ = 0x00;
00268 }
00269
00270
00271 static unsigned char const defaultQuantizers[128] = {
00272
00273 16, 11, 12, 14, 12, 10, 16, 14,
00274 13, 14, 18, 17, 16, 19, 24, 40,
00275 26, 24, 22, 22, 24, 49, 35, 37,
00276 29, 40, 58, 51, 61, 60, 57, 51,
00277 56, 55, 64, 72, 92, 78, 64, 68,
00278 87, 69, 55, 56, 80, 109, 81, 87,
00279 95, 98, 103, 104, 103, 62, 77, 113,
00280 121, 112, 100, 120, 92, 101, 103, 99,
00281
00282 17, 18, 18, 24, 21, 24, 47, 26,
00283 26, 47, 99, 66, 56, 66, 99, 99,
00284 99, 99, 99, 99, 99, 99, 99, 99,
00285 99, 99, 99, 99, 99, 99, 99, 99,
00286 99, 99, 99, 99, 99, 99, 99, 99,
00287 99, 99, 99, 99, 99, 99, 99, 99,
00288 99, 99, 99, 99, 99, 99, 99, 99,
00289 99, 99, 99, 99, 99, 99, 99, 99
00290 };
00291
00292 static void makeDefaultQtables(unsigned char* resultTables, unsigned Q) {
00293 int factor = Q;
00294 int q;
00295
00296 if (Q < 1) factor = 1;
00297 else if (Q > 99) factor = 99;
00298
00299 if (Q < 50) {
00300 q = 5000 / factor;
00301 } else {
00302 q = 200 - factor*2;
00303 }
00304
00305 for (int i = 0; i < 128; ++i) {
00306 int newVal = (defaultQuantizers[i]*q + 50)/100;
00307 if (newVal < 1) newVal = 1;
00308 else if (newVal > 255) newVal = 255;
00309 resultTables[i] = newVal;
00310 }
00311 }
00312
00313 Boolean JPEGVideoRTPSource
00314 ::processSpecialHeader(BufferedPacket* packet,
00315 unsigned& resultSpecialHeaderSize) {
00316 unsigned char* headerStart = packet->data();
00317 unsigned packetSize = packet->dataSize();
00318
00319 unsigned char* qtables = NULL;
00320 unsigned qtlen = 0;
00321 unsigned dri = 0;
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 if (packetSize < 8) return False;
00334
00335 resultSpecialHeaderSize = 8;
00336
00337 unsigned Offset = (unsigned)((DWORD)headerStart[1] << 16 | (DWORD)headerStart[2] << 8 | (DWORD)headerStart[3]);
00338 unsigned Type = (unsigned)headerStart[4];
00339 unsigned type = Type & 1;
00340 unsigned Q = (unsigned)headerStart[5];
00341 unsigned width = (unsigned)headerStart[6] * 8;
00342 unsigned height = (unsigned)headerStart[7] * 8;
00343 if ((width == 0 || height == 0) && fDefaultWidth != 0 && fDefaultHeight != 0) {
00344
00345 width = fDefaultWidth;
00346 height = fDefaultHeight;
00347 }
00348 if (width == 0) width = 256*8;
00349 if (height == 0) height = 256*8;
00350
00351 if (Type > 63) {
00352
00353
00354
00355
00356
00357
00358
00359
00360 if (packetSize < resultSpecialHeaderSize + 4) return False;
00361
00362 unsigned RestartInterval = (unsigned)((WORD)headerStart[resultSpecialHeaderSize] << 8 | (WORD)headerStart[resultSpecialHeaderSize + 1]);
00363 dri = RestartInterval;
00364 resultSpecialHeaderSize += 4;
00365 }
00366
00367 if (Offset == 0) {
00368 if (Q > 127) {
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 if (packetSize < resultSpecialHeaderSize + 4) return False;
00381
00382 unsigned MBZ = (unsigned)headerStart[resultSpecialHeaderSize];
00383 if (MBZ == 0) {
00384
00385 unsigned Length = (unsigned)((WORD)headerStart[resultSpecialHeaderSize + 2] << 8 | (WORD)headerStart[resultSpecialHeaderSize + 3]);
00386
00387
00388
00389 resultSpecialHeaderSize += 4;
00390
00391 if (packetSize < resultSpecialHeaderSize + Length) return False;
00392
00393 qtlen = Length;
00394 qtables = &headerStart[resultSpecialHeaderSize];
00395
00396 resultSpecialHeaderSize += Length;
00397 }
00398 }
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 if (Offset == 0) {
00410 unsigned char newQtables[128];
00411 if (qtlen == 0) {
00412
00413
00414 makeDefaultQtables(newQtables, Q);
00415 qtables = newQtables;
00416 qtlen = sizeof newQtables;
00417 }
00418
00419 unsigned hdrlen = computeJPEGHeaderSize(qtlen, dri);
00420 resultSpecialHeaderSize -= hdrlen;
00421 headerStart += (int)resultSpecialHeaderSize;
00422 createJPEGHeader(headerStart, type, width, height, qtables, qtlen, dri);
00423 }
00424
00425 fCurrentPacketBeginsFrame = (Offset == 0);
00426
00427
00428 ((JPEGBufferedPacket*)packet)->completesFrame
00429 = fCurrentPacketCompletesFrame = packet->rtpMarkerBit();
00430
00431 return True;
00432 }
00433
00434 char const* JPEGVideoRTPSource::MIMEtype() const {
00435 return "video/JPEG";
00436 }
00437
00439
00440 void JPEGBufferedPacket::reset() {
00441 BufferedPacket::reset();
00442
00443
00444
00445 unsigned offset = MAX_JPEG_HEADER_SIZE;
00446 if (offset > fPacketSize) offset = fPacketSize;
00447 fHead = fTail = offset;
00448 }
00449
00450 unsigned JPEGBufferedPacket
00451 ::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) {
00452
00453
00454 if (completesFrame && dataSize >= 2 &&
00455 !(framePtr[dataSize-2] == 0xFF && framePtr[dataSize-1] == MARKER_EOI)) {
00456 framePtr[dataSize++] = 0xFF;
00457 framePtr[dataSize++] = MARKER_EOI;
00458 }
00459 return dataSize;
00460 }
00461
00462 BufferedPacket* JPEGBufferedPacketFactory
00463 ::createNewPacket(MultiFramedRTPSource* ) {
00464 return new JPEGBufferedPacket;
00465 }