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

mxcpcFramewiseMxPEGDecoder.cpp

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

Generated on Fri Jan 20 13:33:32 2006 for mxcpc by  doxygen 1.4.4