MythTV  0.26-pre
JPEGVideoRTPSource.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends