|
MythTV
0.26-pre
|
00001 /********** 00002 This library is free software; you can redistribute it and/or modify it under 00003 the terms of the GNU Lesser General Public License as published by the 00004 Free Software Foundation; either version 2.1 of the License, or (at your 00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) 00006 00007 This library is distributed in the hope that it will be useful, but WITHOUT 00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00009 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 00010 more details. 00011 00012 You should have received a copy of the GNU Lesser General Public License 00013 along with this library; if not, write to the Free Software Foundation, Inc., 00014 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00015 **********/ 00016 // "liveMedia" 00017 // Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. 00018 00019 // JPEG Video (RFC 2435) RTP Sources 00020 // Implementation 00021 // 09 26 2002 - Initial Implementation : Giom 00022 // Copyright (c) 1990-2002 Morgan Multimedia All rights reserved. 00023 00024 // 02/2003: Cleaned up to add the synthesized JPEG header to the start 00025 // of each incoming frame. 00026 // Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. 00027 00028 #include "JPEGVideoRTPSource.hh" 00029 00031 00032 class JPEGBufferedPacket: public BufferedPacket { 00033 public: 00034 Boolean completesFrame; 00035 00036 private: 00037 // Redefined virtual functions: 00038 virtual void reset(); 00039 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, 00040 unsigned dataSize); 00041 }; 00042 00043 class JPEGBufferedPacketFactory: public BufferedPacketFactory { 00044 private: // redefined virtual functions 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, // start-of-frame, baseline scan 00077 MARKER_SOI = 0xd8, // start of image 00078 MARKER_EOI = 0xd9, // end of image 00079 MARKER_SOS = 0xda, // start of scan 00080 MARKER_DRI = 0xdd, // restart interval 00081 MARKER_DQT = 0xdb, // define quantization tables 00082 MARKER_DHT = 0xc4, // huffman tables 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; /* length msb */ 00168 *p++ = 3 + ncodes + nsymbols; /* length lsb */ 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; // in case qtlen is odd; shouldn't happen 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 // MARKER_SOI: 00189 *ptr++ = 0xFF; *ptr++ = MARKER_SOI; 00190 00191 // MARKER_APP_FIRST: 00192 *ptr++ = 0xFF; *ptr++ = MARKER_APP_FIRST; 00193 *ptr++ = 0x00; *ptr++ = 0x10; // size of chunk 00194 *ptr++ = 'J'; *ptr++ = 'F'; *ptr++ = 'I'; *ptr++ = 'F'; *ptr++ = 0x00; 00195 *ptr++ = 0x01; *ptr++ = 0x01; // JFIF format version (1.1) 00196 *ptr++ = 0x00; // no units 00197 *ptr++ = 0x00; *ptr++ = 0x01; // Horizontal pixel aspect ratio 00198 *ptr++ = 0x00; *ptr++ = 0x01; // Vertical pixel aspect ratio 00199 *ptr++ = 0x00; *ptr++ = 0x00; // no thumbnail 00200 00201 // MARKER_DRI: 00202 if (dri > 0) { 00203 *ptr++ = 0xFF; *ptr++ = MARKER_DRI; 00204 *ptr++ = 0x00; *ptr++ = 0x04; // size of chunk 00205 *ptr++ = (BYTE)(dri >> 8); *ptr++ = (BYTE)(dri); // restart interval 00206 } 00207 00208 // MARKER_DQT (luma): 00209 unsigned tableSize = numQtables == 1 ? qtlen : qtlen/2; 00210 *ptr++ = 0xFF; *ptr++ = MARKER_DQT; 00211 *ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk 00212 *ptr++ = 0x00; // precision(0), table id(0) 00213 memcpy(ptr, qtables, tableSize); 00214 qtables += tableSize; 00215 ptr += tableSize; 00216 00217 if (numQtables > 1) { 00218 unsigned tableSize = qtlen - qtlen/2; 00219 // MARKER_DQT (chroma): 00220 *ptr++ = 0xFF; *ptr++ = MARKER_DQT; 00221 *ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk 00222 *ptr++ = 0x01; // precision(0), table id(1) 00223 memcpy(ptr, qtables, tableSize); 00224 qtables += tableSize; 00225 ptr += tableSize; 00226 } 00227 00228 // MARKER_SOF0: 00229 *ptr++ = 0xFF; *ptr++ = MARKER_SOF0; 00230 *ptr++ = 0x00; *ptr++ = 0x11; // size of chunk 00231 *ptr++ = 0x08; // sample precision 00232 *ptr++ = (BYTE)(h >> 8); 00233 *ptr++ = (BYTE)(h); // number of lines (must be a multiple of 8) 00234 *ptr++ = (BYTE)(w >> 8); 00235 *ptr++ = (BYTE)(w); // number of columns (must be a multiple of 8) 00236 *ptr++ = 0x03; // number of components 00237 *ptr++ = 0x01; // id of component 00238 *ptr++ = type ? 0x22 : 0x21; // sampling ratio (h,v) 00239 *ptr++ = 0x00; // quant table id 00240 *ptr++ = 0x02; // id of component 00241 *ptr++ = 0x11; // sampling ratio (h,v) 00242 *ptr++ = numQtables == 1 ? 0x00 : 0x01; // quant table id 00243 *ptr++ = 0x03; // id of component 00244 *ptr++ = 0x11; // sampling ratio (h,v) 00245 *ptr++ = 0x01; // quant table id 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 // MARKER_SOS: 00257 *ptr++ = 0xFF; *ptr++ = MARKER_SOS; 00258 *ptr++ = 0x00; *ptr++ = 0x0C; // size of chunk 00259 *ptr++ = 0x03; // number of components 00260 *ptr++ = 0x01; // id of component 00261 *ptr++ = 0x00; // huffman table id (DC, AC) 00262 *ptr++ = 0x02; // id of component 00263 *ptr++ = 0x11; // huffman table id (DC, AC) 00264 *ptr++ = 0x03; // id of component 00265 *ptr++ = 0x11; // huffman table id (DC, AC) 00266 *ptr++ = 0x00; // start of spectral 00267 *ptr++ = 0x3F; // end of spectral 00268 *ptr++ = 0x00; // successive approximation bit position (high, low) 00269 } 00270 00271 // The default 'luma' and 'chroma' quantizer tables, in zigzag order: 00272 static unsigned char const defaultQuantizers[128] = { 00273 // luma table: 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 // chroma table: 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 // There's at least 8-byte video-specific header 00325 /* 00326 0 1 2 3 00327 0 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 00328 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00329 | Type-specific | Fragment Offset | 00330 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00331 | Type | Q | Width | Height | 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; // special case 00344 unsigned height = (unsigned)headerStart[7] * 8; 00345 if (height == 0) height = 256*8; // special case 00346 00347 if (Type > 63) { 00348 // Restart Marker header present 00349 /* 00350 0 1 2 3 00351 0 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 00352 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00353 | Restart Interval |F|L| Restart Count | 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 // Quantization Table header present 00366 /* 00367 0 1 2 3 00368 0 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 00369 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00370 | MBZ | Precision | Length | 00371 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00372 | Quantization Table Data | 00373 | ... | 00374 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00375 */ 00376 if (packetSize < resultSpecialHeaderSize + 4) return False; 00377 00378 unsigned MBZ = (unsigned)headerStart[resultSpecialHeaderSize]; 00379 if (MBZ == 0) { 00380 // unsigned Precision = (unsigned)headerStart[resultSpecialHeaderSize + 1]; 00381 unsigned Length = (unsigned)((WORD)headerStart[resultSpecialHeaderSize + 2] << 8 | (WORD)headerStart[resultSpecialHeaderSize + 3]); 00382 00383 //ASSERT(Length == 128); 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 // If this is the first (or only) fragment of a JPEG frame, then we need 00400 // to synthesize a JPEG header, and prepend it to the incoming data. 00401 // Hack: We can do this because we allowed space for it in 00402 // our special "JPEGBufferedPacket" subclass. We also adjust 00403 // "resultSpecialHeaderSize" to compensate for this, by subtracting 00404 // the size of the synthesized header. Note that this will cause 00405 // "resultSpecialHeaderSize" to become negative, but the code that called 00406 // us (in "MultiFramedRTPSource") will handle this properly. 00407 if (Offset == 0) { 00408 unsigned char newQtables[128]; 00409 if (qtlen == 0) { 00410 // A quantization table was not present in the RTP JPEG header, 00411 // so use the default tables, scaled according to the "Q" factor: 00412 makeDefaultQtables(newQtables, Q); 00413 qtables = newQtables; 00414 qtlen = sizeof newQtables; 00415 } 00416 00417 unsigned hdrlen = computeJPEGHeaderSize(qtlen, dri); 00418 resultSpecialHeaderSize -= hdrlen; // goes negative 00419 headerStart += (int)resultSpecialHeaderSize; // goes backward 00420 createJPEGHeader(headerStart, type, width, height, qtables, qtlen, dri); 00421 } 00422 00423 fCurrentPacketBeginsFrame = (Offset == 0); 00424 00425 // The RTP "M" (marker) bit indicates the last fragment of a frame: 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 // Move our "fHead" and "fTail" forward, to allow space for a synthesized 00442 // JPEG header to precede the RTP data that comes in over the network. 00443 unsigned offset = MAX_JPEG_HEADER_SIZE; 00444 if (offset > fPacketSize) offset = fPacketSize; // shouldn't happen 00445 fHead = fTail = offset; 00446 } 00447 00448 unsigned JPEGBufferedPacket 00449 ::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { 00450 // Normally, the enclosed frame size is just "dataSize". If, however, 00451 // the frame does not end with the "EOI" marker, then add this now: 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* /*ourSource*/) { 00462 return new JPEGBufferedPacket; 00463 }
1.7.6.1