liveMedia/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 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
00018 // JPEG Video (RFC 2435) RTP Sources
00019 // Implementation
00020 
00021 #include "JPEGVideoRTPSource.hh"
00022 
00024 
00025 class JPEGBufferedPacket: public BufferedPacket {
00026 public:
00027   Boolean completesFrame;
00028 
00029 private:
00030   // Redefined virtual functions:
00031   virtual void reset();
00032   virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
00033                                          unsigned dataSize);
00034 };
00035 
00036 class JPEGBufferedPacketFactory: public BufferedPacketFactory {
00037 private: // redefined virtual functions
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,         // start-of-frame, baseline scan
00073         MARKER_SOI      = 0xd8,         // start of image
00074         MARKER_EOI      = 0xd9,         // end of image
00075         MARKER_SOS      = 0xda,         // start of scan
00076         MARKER_DRI      = 0xdd,         // restart interval
00077         MARKER_DQT      = 0xdb,         // define quantization tables
00078         MARKER_DHT  = 0xc4,             // huffman tables
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;               /* length msb */
00164   *p++ = 3 + ncodes + nsymbols; /* length lsb */
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; // in case qtlen is odd; shouldn't happen
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   // MARKER_SOI:
00188   *ptr++ = 0xFF; *ptr++ = MARKER_SOI;
00189 
00190   // MARKER_APP_FIRST:
00191   *ptr++ = 0xFF; *ptr++ = MARKER_APP_FIRST;
00192   *ptr++ = 0x00; *ptr++ = 0x10; // size of chunk
00193   *ptr++ = 'J'; *ptr++ = 'F'; *ptr++ = 'I'; *ptr++ = 'F'; *ptr++ = 0x00;
00194   *ptr++ = 0x01; *ptr++ = 0x01; // JFIF format version (1.1)
00195   *ptr++ = 0x00; // no units
00196   *ptr++ = 0x00; *ptr++ = 0x01; // Horizontal pixel aspect ratio
00197   *ptr++ = 0x00; *ptr++ = 0x01; // Vertical pixel aspect ratio
00198   *ptr++ = 0x00; *ptr++ = 0x00; // no thumbnail
00199 
00200   // MARKER_DRI:
00201   if (dri > 0) {
00202     *ptr++ = 0xFF; *ptr++ = MARKER_DRI;
00203     *ptr++ = 0x00; *ptr++ = 0x04; // size of chunk
00204     *ptr++ = (BYTE)(dri >> 8); *ptr++ = (BYTE)(dri); // restart interval
00205   }
00206 
00207   // MARKER_DQT (luma):
00208   unsigned tableSize = numQtables == 1 ? qtlen : qtlen/2;
00209   *ptr++ = 0xFF; *ptr++ = MARKER_DQT;
00210   *ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk
00211   *ptr++ = 0x00; // precision(0), table id(0)
00212   memcpy(ptr, qtables, tableSize);
00213   qtables += tableSize;
00214   ptr += tableSize;
00215 
00216   if (numQtables > 1) {
00217     unsigned tableSize = qtlen - qtlen/2;
00218     // MARKER_DQT (chroma):
00219     *ptr++ = 0xFF; *ptr++ = MARKER_DQT;
00220     *ptr++ = 0x00; *ptr++ = tableSize + 3; // size of chunk
00221     *ptr++ = 0x01; // precision(0), table id(1)
00222     memcpy(ptr, qtables, tableSize);
00223     qtables += tableSize;
00224     ptr += tableSize;
00225   }
00226 
00227   // MARKER_SOF0:
00228   *ptr++ = 0xFF; *ptr++ = MARKER_SOF0;
00229   *ptr++ = 0x00; *ptr++ = 0x11; // size of chunk
00230   *ptr++ = 0x08; // sample precision
00231   *ptr++ = (BYTE)(h >> 8);
00232   *ptr++ = (BYTE)(h); // number of lines (must be a multiple of 8)
00233   *ptr++ = (BYTE)(w >> 8);
00234   *ptr++ = (BYTE)(w); // number of columns (must be a multiple of 8)
00235   *ptr++ = 0x03; // number of components
00236   *ptr++ = 0x01; // id of component
00237   *ptr++ = type ? 0x22 : 0x21; // sampling ratio (h,v)
00238   *ptr++ = 0x00; // quant table id
00239   *ptr++ = 0x02; // id of component
00240   *ptr++ = 0x11; // sampling ratio (h,v)
00241   *ptr++ = numQtables == 1 ? 0x00 : 0x01; // quant table id
00242   *ptr++ = 0x03; // id of component
00243   *ptr++ = 0x11; // sampling ratio (h,v)
00244   *ptr++ = numQtables == 1 ? 0x00 : 0x01; // quant table id
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   // MARKER_SOS:
00256   *ptr++ = 0xFF;  *ptr++ = MARKER_SOS;
00257   *ptr++ = 0x00; *ptr++ = 0x0C; // size of chunk
00258   *ptr++ = 0x03; // number of components
00259   *ptr++ = 0x01; // id of component
00260   *ptr++ = 0x00; // huffman table id (DC, AC)
00261   *ptr++ = 0x02; // id of component
00262   *ptr++ = 0x11; // huffman table id (DC, AC)
00263   *ptr++ = 0x03; // id of component
00264   *ptr++ = 0x11; // huffman table id (DC, AC)
00265   *ptr++ = 0x00; // start of spectral
00266   *ptr++ = 0x3F; // end of spectral
00267   *ptr++ = 0x00; // successive approximation bit position (high, low)
00268 }
00269 
00270 // The default 'luma' and 'chroma' quantizer tables, in zigzag order:
00271 static unsigned char const defaultQuantizers[128] = {
00272   // luma table:
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   // chroma table:
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   // There's at least 8-byte video-specific header
00324   /*
00325 0                   1                   2                   3
00326 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
00327 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00328 | Type-specific |              Fragment Offset                  |
00329 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00330 |      Type     |       Q       |     Width     |     Height    |
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     // Use the default width and height parameters instead:
00345     width = fDefaultWidth;
00346     height = fDefaultHeight;
00347   }
00348   if (width == 0) width = 256*8; // special case
00349   if (height == 0) height = 256*8; // special case
00350 
00351   if (Type > 63) {
00352     // Restart Marker header present
00353     /*
00354 0                   1                   2                   3
00355 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
00356 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00357 |       Restart Interval        |F|L|       Restart Count       |
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       // Quantization Table header present
00370 /*
00371 0                   1                   2                   3
00372 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
00373 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00374 |      MBZ      |   Precision   |             Length            |
00375 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00376 |                    Quantization Table Data                    |
00377 |                              ...                              |
00378 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00379 */
00380       if (packetSize < resultSpecialHeaderSize + 4) return False;
00381 
00382       unsigned MBZ = (unsigned)headerStart[resultSpecialHeaderSize];
00383       if (MBZ == 0) {
00384         // unsigned Precision = (unsigned)headerStart[resultSpecialHeaderSize + 1];
00385         unsigned Length = (unsigned)((WORD)headerStart[resultSpecialHeaderSize + 2] << 8 | (WORD)headerStart[resultSpecialHeaderSize + 3]);
00386 
00387         //ASSERT(Length == 128);
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   // If this is the first (or only) fragment of a JPEG frame, then we need
00402   // to synthesize a JPEG header, and prepend it to the incoming data.
00403   // Hack: We can do this because we allowed space for it in
00404   // our special "JPEGBufferedPacket" subclass.  We also adjust
00405   // "resultSpecialHeaderSize" to compensate for this, by subtracting
00406   // the size of the synthesized header.  Note that this will cause
00407   // "resultSpecialHeaderSize" to become negative, but the code that called
00408   // us (in "MultiFramedRTPSource") will handle this properly.
00409   if (Offset == 0) {
00410     unsigned char newQtables[128];
00411     if (qtlen == 0) {
00412       // A quantization table was not present in the RTP JPEG header,
00413       // so use the default tables, scaled according to the "Q" factor:
00414       makeDefaultQtables(newQtables, Q);
00415       qtables = newQtables;
00416       qtlen = sizeof newQtables;
00417     }
00418 
00419     unsigned hdrlen = computeJPEGHeaderSize(qtlen, dri);
00420     resultSpecialHeaderSize -= hdrlen; // goes negative
00421     headerStart += (int)resultSpecialHeaderSize; // goes backward
00422     createJPEGHeader(headerStart, type, width, height, qtables, qtlen, dri);
00423   }
00424 
00425   fCurrentPacketBeginsFrame = (Offset == 0);
00426 
00427   // The RTP "M" (marker) bit indicates the last fragment of a frame:
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   // Move our "fHead" and "fTail" forward, to allow space for a synthesized
00444   // JPEG header to precede the RTP data that comes in over the network.
00445   unsigned offset = MAX_JPEG_HEADER_SIZE;
00446   if (offset > fPacketSize) offset = fPacketSize; // shouldn't happen
00447   fHead = fTail = offset;
00448 }
00449 
00450 unsigned JPEGBufferedPacket
00451 ::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) {
00452   // Normally, the enclosed frame size is just "dataSize".  If, however,
00453   // the frame does not end with the "EOI" marker, then add this now:
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* /*ourSource*/) {
00464   return new JPEGBufferedPacket;
00465 }

Generated on Mon Apr 29 13:28:01 2013 for live by  doxygen 1.5.2