Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members

mxcpcFramewiseMxPEGDecoder.cpp

00001 //           ///          //
00002 //          /////        ////
00003 //         /// XXX     XXX ///
00004 //        ///    XXX XXX    ///     $RCSfile: mxcpcFramewiseMxPEGDecoder.cpp,v $  
00005 //       ///       XXX       ///     $Revision: 1.7 $
00006 //      ///      XXX XXX      ///     $Date: 2005/08/09 13:57:26 $
00007 //     ////    XXX     XXX    ////     $Author: cvs-steve $
00008 //    ////                     ////
00009 //   ////  M  O  B  O  T  I  X  ////////////////////////////////////////////////
00010 //  //// Security Vision Systems ///////////////////////////////////////////////
00011 
00012 // Copyright (c) 2005, MOBOTIX AG.
00013 // This software is made available under the BSD licence. Please refer 
00014 // to the file LICENCE.TXT contained in this distribution for details.
00015 
00016 
00017 #include <mxcpcFramewiseMxPEGDecoder.h>
00018 #include <mxcpcFramewiseMxPEGScanDecoder.h>
00019 #include <mxcpcStreamSource.h>
00020 #include <mxcpcMxPEGDecoderBackEnd.h>
00021 #include <mxcpc_exceptions.h>
00022 #include <mxcpc_namespace.h>
00023 
00024 #include <exception>
00025 #include <cstdio>
00026 #include <cstring>
00027 #include <cstdlib>
00028 
00029 #ifdef WIN32
00030 #include <fcntl.h>
00031 #include <io.h>
00032 #else
00033 #include <unistd.h>
00034 #endif
00035 
00036 
00037 mxcpcFramewiseMxPEGDecoder::mxcpcFramewiseMxPEGDecoder(mxcpcStreamSource *source,
00038                                                        mxcpcMxPEGDecoderBackEnd *backend,
00039                                                        mxcpcFramewiseMxPEGScanDecoder 
00040                                                         *scan_decoder)
00041                              : mxcpcMxPEGDecoder(source, backend)                         {
00042                                                 
00043   PrefetchBuffSize = 6 * 64 * 1024;
00044   PrefetchedBytes = 0;
00045   
00046   PrefetchBuffer = 0;
00047   try {
00048   
00049     PrefetchBuffer = new unsigned char[PrefetchBuffSize];
00050     
00051   } catch(std::exception &e) {
00052     
00053       MXCPC_RETHROW_UNHANDLED_EXCEPTION(e);
00054       
00055       delete[] PrefetchBuffer;
00056       
00057       throw;
00058     }
00059   
00060   // --- init state machine datafields... ---
00061     
00062   State = AwaitSOI;
00063   
00064   CurrentBytePtr = 0;
00065   BytesLeft = 0;
00066   
00067   AwaitMarkerStage = 0;
00068   
00069   ReadMarkerStage = 0;
00070   ReadMarkerFirstLenByte = 0;
00071   MarkerBytesNeeded = 0;
00072   
00073   ScanStage = 0;
00074   
00075   MarkerPayload = 0;
00076   
00077   Width = Height = 0;
00078   ScanDecoder = scan_decoder;
00079   ScanDecoder->setBackEnd(backend);
00080 }
00081 
00082 
00083 mxcpcFramewiseMxPEGDecoder::~mxcpcFramewiseMxPEGDecoder() {
00084 
00085   delete[] PrefetchBuffer;
00086   delete   ScanDecoder;
00087 }
00088 
00089 
00090 
00091 int mxcpcFramewiseMxPEGDecoder::decode(int num) {
00092 
00093   int bytes_allowed;
00094   unsigned char *buff_ptr;
00095   int bytes_read, bytes_processed;
00096   
00097   // determine max no of bytes to process for this call...
00098   bytes_allowed = PrefetchBuffSize - PrefetchedBytes;
00099   if(bytes_allowed > num) bytes_allowed = num;
00100   if(bytes_allowed < 1) {
00101     mxcpc::sendStatusMsg("!!! MxPEG decoder failure (prefetch buffer overflow) !!!", this);
00102     std::exit(666);
00103     //return(0);
00104   }  
00105   
00106   bytes_processed = 0;
00107   while(bytes_allowed > 0) {
00108    
00109     buff_ptr = PrefetchBuffer + PrefetchedBytes;
00110     bytes_read = StreamSource->fetchBytes(buff_ptr, bytes_allowed); 
00111     if(!bytes_read) break;
00112     
00113     PrefetchedBytes += bytes_read;
00114    
00115     feedBytes(buff_ptr, bytes_read);   // might remove entire frame image and
00116                                        // thus modify _PrefetchedBytes_ variable
00117     
00118     bytes_processed += bytes_read;
00119     bytes_allowed   -= bytes_read;
00120   } 
00121   
00122   return(bytes_processed);
00123 }
00124 
00125 
00126 void mxcpcFramewiseMxPEGDecoder::feedBytes(unsigned char *buffer,
00127                                            int num) {
00128   
00129   unsigned char marker_type;
00130   int width, height;
00131   bool need_to_copy_down;
00132 
00133   if(num < 1) return;
00134   
00135   CurrentBytePtr = buffer;
00136   BytesLeft = num;
00137   while(BytesLeft) {
00138     need_to_copy_down = false;
00139   
00140     switch(State) {
00141     
00142       // all these states can digest BytesLeft == 0
00143     
00144       case AwaitSOI:
00145         if(!awaitMarker(&marker_type)) return;
00146         if(marker_type == 0xd8)   // SOI marker 
00147           State = AwaitAPP0;
00148         else
00149           State = No_Good_State;
00150         break;
00151         
00152       case AwaitAPP0:
00153         if(!awaitMarker(&marker_type)) return;
00154         if(marker_type == 0xe0)
00155           State = APP0;
00156         else
00157           State = No_Good_State;
00158         break;
00159         
00160       case APP0:
00161         if(!readMarkerPayload()) return;
00162         State = Determine_FingerPrint_Or_FrameHeader;
00163         break;
00164         
00165       case Determine_FingerPrint_Or_FrameHeader:
00166         if(!awaitMarker(&marker_type)) return;
00167         if(marker_type == 0xfe) State = Determine_FingerPrint_Or_FrameHeader2;
00168         else                    State = No_Good_State;
00169         break;
00170         
00171       case Determine_FingerPrint_Or_FrameHeader2:
00172         if(!readMarkerPayload()) return;  
00173         if(!strncmp((char *)MarkerPayload, "#:M1IMG", 7)) 
00174           State = FingerPrint;
00175         else if(!strncmp((char *)MarkerPayload, "MXF", 3)) 
00176           State = FrameHeader;
00177         else
00178           State = No_Good_State;      
00179         break;
00180         
00181       case FingerPrint:
00182         State = AwaitFrameHeader;
00183         break;
00184          
00185       case AwaitFrameHeader:
00186         if(!awaitMarker(&marker_type)) return;
00187         if(marker_type == 0xfe)
00188           State = AwaitFrameHeader2;
00189         else
00190           State = No_Good_State;
00191         break;
00192          
00193       case AwaitFrameHeader2:
00194         if(!readMarkerPayload()) return;  
00195         if(!strncmp((char *)MarkerPayload, "MXF", 3))
00196           State = FrameHeader;
00197         else
00198           State = No_Good_State; 
00199         break;
00200         
00201       case FrameHeader:
00202         State = BitMask_Or_Tables;
00203         break;
00204         
00205       case BitMask_Or_Tables:
00206         if(!awaitMarker(&marker_type)) return;
00207         if(marker_type == 0xdb) {
00208           FrameDescriptor.TileBits = 0;
00209           State = QuantizationTable1;
00210         }
00211         else if(marker_type == 0xfe)
00212           State = BitMask;
00213         else
00214           State = No_Good_State;
00215         break;
00216         
00217       case QuantizationTable1:
00218         if(!readMarkerPayload()) return;
00219         ScanDecoder->setYQuantizationTable(&MarkerPayload[1]);
00220         State = AwaitQuantizationTable2;
00221         break;
00222         
00223       case AwaitQuantizationTable2:
00224         if(!awaitMarker(&marker_type)) return;
00225         if(marker_type == 0xdb)
00226           State = QuantizationTable2;
00227         else
00228           State = No_Good_State;
00229         break;
00230      
00231       case QuantizationTable2:
00232         if(!readMarkerPayload()) return;
00233         ScanDecoder->setUVQuantizationTable(&MarkerPayload[1]);
00234         State = Huffman_Or_SOF;
00235         break;
00236      
00237       case Huffman_Or_SOF:
00238         if(!awaitMarker(&marker_type)) return;
00239         if(marker_type == 0xc4)
00240           State = HuffmanTable;
00241         else if(marker_type == 0xc0)
00242           State = SOF;
00243         else 
00244           State = No_Good_State;
00245         break;
00246         
00247       case SOF:
00248         if(!readMarkerPayload()) return;
00249         width  = (int)MarkerPayload[3]*256 + (int)MarkerPayload[4];
00250         height = (int)MarkerPayload[1]*256 + (int)MarkerPayload[2];
00251         FrameDescriptor.setResolution(width, height);
00252         State = Huffman_Or_Scan;
00253         break;
00254         
00255       case HuffmanTable:
00256         if(!readMarkerPayload()) return;
00257         State = Huffman_Or_Scan;
00258         break;
00259         
00260       case Huffman_Or_Scan:
00261         if(!awaitMarker(&marker_type)) return;
00262         if(marker_type == 0xda)
00263           State = Scan;
00264         else if(marker_type == 0xc4)
00265           State = HuffmanTable;
00266         else 
00267           State = No_Good_State;
00268         break;
00269         
00270       case Scan:
00271         if(!readMarkerPayload()) return;
00272         FrameDescriptor.ScanBytes = CurrentBytePtr;
00273         State = Scan2;
00274         break;
00275         
00276       case Scan2:
00277         if(!doScan()) return;
00278         FrameDescriptor.ScanLength = CurrentBytePtr - FrameDescriptor.ScanBytes;
00279         State = Audio_Or_SOI;
00280         break;
00281         
00282       case BitMask:
00283         if(!readMarkerPayload()) return;
00284         FrameDescriptor.TileBits = &MarkerPayload[12];
00285         State = Tables_Or_Scan;
00286         break;
00287         
00288       case Tables_Or_Scan:
00289         if(!awaitMarker(&marker_type)) return;
00290         if(marker_type == 0xdb)
00291           State = QuantizationTable1;
00292         else if(marker_type == 0xda)
00293           State = Scan;
00294         else
00295           State = No_Good_State;
00296         break;
00297         
00298       case Audio_Or_SOI:
00299         if(!awaitMarker(&marker_type)) {
00300     return;
00301   }
00302         if(marker_type == 0xed)
00303           State = Audio;
00304         else if(marker_type == 0xd8) {
00305           need_to_copy_down = true;
00306           State = AwaitAPP0;
00307         }
00308         else {
00309           need_to_copy_down = true;
00310           State = No_Good_State;
00311         }
00312         break;
00313         
00314       case Audio:
00315         if(!readMarkerPayload()) return;
00316         need_to_copy_down = true;
00317         State = AwaitSOI;
00318         break;
00319         
00320       case No_Good_State:
00321         mxcpc::sendStatusMsg("!!! MxPEG decoder failure (no_good_state) !!!", this);
00322         std::exit(666);
00323         break;
00324         
00325       default:
00326         mxcpc::sendStatusMsg("!!! MxPEG decoder INTERNAL FAILURE !!!");
00327         std::exit(666);
00328         break;        
00329     }
00330     
00331     if(need_to_copy_down) {   
00332     
00333       // ---------- we've got one complete undecoded frame image ----------
00334   
00335       // check video resolution...
00336       if(   (FrameDescriptor.Width != Width)
00337          || (FrameDescriptor.Height != Height)) {
00338          
00339         BackEnd->videoResolutionChanged(FrameDescriptor.Width,
00340                                         FrameDescriptor.Height);
00341         Width  = FrameDescriptor.Width;
00342         Height = FrameDescriptor.Height;
00343       }
00344 
00345       //QTime t;
00346       //t.start();      
00347       ScanDecoder->performScanSweep(&FrameDescriptor);
00348       //std::printf("time needed for scan decode : %dms\n", t.elapsed());          
00349              
00350       BackEnd->frameComplete();
00351                                        
00352       // copy down remainder of prefetched bytes...
00353       if(BytesLeft) {
00354         std::memmove(PrefetchBuffer, CurrentBytePtr, BytesLeft);   // could overlap
00355       }
00356       CurrentBytePtr = PrefetchBuffer;
00357       PrefetchedBytes = BytesLeft;
00358         // _need_to_copy_down_ flag will be cleared first thing in the next
00359         // loop cycle...
00360         
00361       // prepare for new attack run...
00362       FrameDescriptor.reset(Width, Height);
00363     }
00364   }
00365 }
00366 
00367 
00376 bool mxcpcFramewiseMxPEGDecoder::awaitMarker(unsigned char *marker_type) {
00377   
00378   if(AwaitMarkerStage == 0) {   // nothing found yet
00379   
00380     while(BytesLeft) {
00381       if(*CurrentBytePtr == (unsigned char)0xff) {
00382         CurrentBytePtr++;
00383         BytesLeft--;
00384         if(BytesLeft) {
00385           *marker_type = *CurrentBytePtr;
00386           CurrentBytePtr++;
00387           BytesLeft--;
00388           return(true);   // found a marker!
00389         }
00390         else {
00391           // got the 0xff, but no byte left to determine marker type
00392           AwaitMarkerStage = 1;
00393           return(false);
00394         }
00395       }
00396       
00397       CurrentBytePtr++;
00398       BytesLeft--;
00399     }
00400     return(false);   // still nothing!
00401   }   // stage 0
00402   
00403   else {   // stage 1, still net type...
00404     if(BytesLeft) {
00405       *marker_type = *CurrentBytePtr;
00406       CurrentBytePtr++;
00407       BytesLeft--;
00408       AwaitMarkerStage = 0;
00409       return(true);
00410     }
00411     else 
00412       return(false);
00413   }
00414 }
00415 
00416 
00423 bool mxcpcFramewiseMxPEGDecoder::readMarkerPayload(void) {
00424 
00425   for(;;) {
00426     
00427     if(ReadMarkerStage == 0) {   // got nothing
00428       if(!BytesLeft) return(false);
00429       else if(BytesLeft == 1) {
00430         ReadMarkerFirstLenByte = *CurrentBytePtr;
00431         CurrentBytePtr++;
00432         BytesLeft--;
00433         ReadMarkerStage = 1;
00434         return(false);
00435       }
00436       else {  
00437         MarkerBytesNeeded = 256*(int)CurrentBytePtr[0] 
00438                              + (int)CurrentBytePtr[1]
00439                              - 2;
00440         CurrentBytePtr += 2;
00441         BytesLeft -= 2;
00442         MarkerPayload = CurrentBytePtr;
00443         ReadMarkerStage = 2;
00444         continue;
00445       }
00446     }   // stage 0
00447     
00448     else if(ReadMarkerStage == 1) {   // got the 1 length byte, waiting for 2nd 
00449       if(!BytesLeft) return(false);
00450       MarkerBytesNeeded = 256*(int)ReadMarkerFirstLenByte 
00451                            + (int)*CurrentBytePtr
00452                            - 2;
00453       CurrentBytePtr++;
00454       BytesLeft--;
00455       MarkerPayload = CurrentBytePtr;
00456       ReadMarkerStage = 2;
00457       continue;                                
00458     }   // stage 1
00459     
00460     else if(ReadMarkerStage == 2) {   // reading marker payload 
00461       
00462       if(!BytesLeft) return(false);
00463       if(BytesLeft >= MarkerBytesNeeded) {
00464         CurrentBytePtr += MarkerBytesNeeded;
00465         BytesLeft -= MarkerBytesNeeded;
00466         MarkerBytesNeeded = 0;
00467         ReadMarkerFirstLenByte = 0;
00468         ReadMarkerStage = 0;
00469         return(true);
00470       }
00471       else {
00472         MarkerBytesNeeded -= BytesLeft;
00473         CurrentBytePtr += BytesLeft;
00474         BytesLeft = 0;
00475         return(false);
00476       }
00477     }
00478   }
00479 }
00480 
00481 
00485 bool mxcpcFramewiseMxPEGDecoder::doScan(void) {
00486 
00487 label_doScan_begin:
00488 
00489   if(ScanStage == 0) {   // nuffin'
00490     while(BytesLeft) {
00491       if(*CurrentBytePtr == 0xff) {
00492         CurrentBytePtr++;
00493         BytesLeft--;
00494         if(!BytesLeft) {
00495           ScanStage = 1;
00496           return(false);
00497         }
00498         else {
00499           if(*CurrentBytePtr == 0x00) {
00500             CurrentBytePtr++;
00501             BytesLeft--;
00502             continue;
00503           }
00504           else if(*CurrentBytePtr == 0xd9) {   // EOI marker
00505             CurrentBytePtr++;
00506             BytesLeft--;
00507             return(true);
00508           }
00509           else {
00510             mxcpc::sendStatusMsg("!!! MxPEG decoder failure "
00511                                  "(invalid scan termination) !!!");
00512             std::exit(666);
00513           }
00514         }
00515       }
00516       else {
00517         CurrentBytePtr++;
00518         BytesLeft--;
00519       }
00520     }
00521     return(false);
00522   }   // stage 0
00523   
00524   else {   // stage 1 - read a 0xff, decide whether marker or padding
00525     if(!BytesLeft) return(false);
00526     if(*CurrentBytePtr == 0x00) {
00527       CurrentBytePtr++;
00528       BytesLeft--;
00529       ScanStage = 0;
00530       goto label_doScan_begin;   // nasty, but what da hell...
00531     }
00532     else if(*CurrentBytePtr == 0xd9) {   // EOI marker
00533       CurrentBytePtr++;
00534       BytesLeft--;
00535       ScanStage = 0;
00536       return(true);
00537     }
00538     else {
00539       mxcpc::sendStatusMsg("!!! MxPEG decoder failure "
00540                            "(invalid scan termination) !!!");
00541       std::exit(666);
00542     }
00543   }   // stage 1
00544 }
00545 

Generated on Mon Aug 15 03:39:29 2005 for mxcpc by  doxygen 1.4.2-20050421