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