Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

Tools/MessageQueue/LogPlayer.cpp

Go to the documentation of this file.
00001 /**
00002 * @file LogPlayer.cpp
00003 *
00004 * Implementation of class LogPlayer
00005 *
00006 * @author Martin Lötzsch
00007 */
00008 
00009 #include "LogPlayer.h"
00010 #include "Representations/Perception/Image.h"
00011 #include "Representations/Perception/JPEGImage.h"
00012 #include "Representations/Perception/CameraMatrix.h"
00013 #include "Representations/Perception/SpecialPercept.h"
00014 #include "Representations/Cognition/RobotPose.h"
00015 #include "Representations/Cognition/BallModel.h"
00016 #include "Representations/Cognition/PlayerPoseCollection.h"
00017 #include "Representations/Cognition/ObstaclesModel.h"
00018 #include "Representations/Cognition/RobotState.h"
00019 #include "Platform/SystemCall.h"
00020 
00021 LogPlayer::LogPlayer(MessageQueue& targetQueue)
00022 : targetQueue(targetQueue),
00023 smoothingEnabled(false),
00024 playSpeed(1)
00025 {
00026   _new();
00027 }
00028 
00029 void LogPlayer::_new()
00030 {
00031   clear();
00032   stop();
00033   state = initial;
00034 }
00035 
00036 bool LogPlayer::open(const char* fileName)
00037 {
00038   InBinaryFile file(fileName);
00039   if (file.exists())
00040   {
00041     clear();
00042     file >> *this;
00043     stop();
00044     return true;
00045   }
00046   return false;
00047 }
00048 
00049 void LogPlayer::play()
00050 {
00051   pause();
00052   state = playing;
00053 }
00054 
00055 void LogPlayer::stop()
00056 {
00057   pause();
00058   currentMessageNumber = -1;
00059 }
00060 
00061 void LogPlayer::pause()
00062 {
00063   if (getNumberOfMessages() == 0) state = initial;
00064   else state = paused;
00065 
00066   timeOfFirstPlayedMessage = 0;
00067   timeWhenFirstMessageWasPlayed = 0;
00068 }
00069 
00070 void LogPlayer::stepBackward()
00071 {
00072   pause();
00073 
00074   if (state == paused && currentMessageNumber > 0 )
00075     copyMessage(--currentMessageNumber,targetQueue);
00076 }
00077 
00078 void LogPlayer::stepForward()
00079 {
00080   pause();
00081 
00082   if ((state == paused) && (currentMessageNumber < getNumberOfMessages()-1))
00083     copyMessage(++currentMessageNumber,targetQueue);
00084 }
00085 
00086 void LogPlayer::stepRepeat()
00087 {
00088   pause();
00089 
00090   if (state == paused && currentMessageNumber >= 0 )
00091     copyMessage(currentMessageNumber,targetQueue);
00092 }
00093 
00094 void LogPlayer::jumpFrame(int frame)
00095 {
00096   pause();
00097 
00098   if (state == paused && frame >= 1 && frame <= getNumberOfMessages() )
00099     copyMessage(currentMessageNumber = frame - 1,targetQueue);
00100 }
00101 
00102 bool LogPlayer::save(const char* fileName)
00103 {
00104   if (getNumberOfMessages() == 0) return false;
00105 
00106   OutBinaryFile file(fileName);
00107   if (file.exists())
00108   {
00109     file << *this;
00110     return true;
00111   }
00112   return false;
00113 }
00114 
00115 
00116 void LogPlayer::convertIntString(char* str, int value)
00117 {
00118   char temp[256]; 
00119   int i=0;
00120   while(value > 0)
00121   { 
00122     temp[i] = (char)(value % 10) + 48;
00123     value = value / 10; i++;
00124   }
00125   for (int j=i-1; j>=0; j--)
00126     str[j] = temp[i-j-1];
00127   str[i] = '\0';
00128 }
00129 
00130 bool LogPlayer::saveAMV(const char* fileName)
00131 {
00132   if (getNumberOfMessages() == 0) return false;
00133   OutBinaryFile file(fileName);
00134   if (file.exists())
00135   {
00136     unsigned char* imgBuffer;
00137     CameraMatrix cameraMatrix;
00138     Image image;
00139     bool headerGenerated = false;
00140     for (currentMessageNumber=0; currentMessageNumber<getNumberOfMessages();currentMessageNumber++)
00141     {
00142       queue.setSelectedMessageForReading(currentMessageNumber);
00143       if (getCurrentMessageID()==idImage)
00144       {
00145         in.bin >> image >> cameraMatrix;
00146       }
00147       else if (getCurrentMessageID()==idJPEGImage)
00148       {
00149         JPEGImage jpegImage;
00150         in.bin >> jpegImage >> cameraMatrix;
00151         jpegImage.toImage(image);
00152       }
00153       else
00154         continue;
00155       if (!headerGenerated){
00156         char* magicNumber = "AIBOMOVIE";
00157         unsigned char padding = 0;
00158         unsigned char magicNumberLenUTF = 9;
00159         file << padding << magicNumberLenUTF;
00160         for (int k=0; k<magicNumberLenUTF; k++)
00161           file << magicNumber[k];
00162         char widthStr[10];
00163         char heightStr[10];
00164         unsigned char widthLenUTF = 3;
00165         unsigned char heightLenUTF = 3;
00166         convertIntString(widthStr, image.cameraInfo.resolutionWidth);
00167         convertIntString(heightStr, image.cameraInfo.resolutionHeight);
00168         file << padding << widthLenUTF;
00169         for (k=0; k<widthLenUTF; k++)
00170           file << widthStr[k];
00171         file << padding << heightLenUTF;
00172         for (k=0; k<heightLenUTF; k++)
00173           file << heightStr[k];
00174         char movType = '0';
00175         unsigned char movTypeLenUTF = 1;
00176         file << padding << movTypeLenUTF << movType;
00177         imgBuffer = new unsigned char[3*image.cameraInfo.resolutionWidth*image.cameraInfo.resolutionHeight];        
00178         headerGenerated = true;
00179       }
00180     int lineWidth = image.cameraInfo.resolutionWidth;
00181       for (int h=0; h<image.cameraInfo.resolutionHeight; h++)
00182         for (int w=0; w<image.cameraInfo.resolutionWidth; w++)
00183         {
00184           imgBuffer[3*(h*lineWidth + w) + 0] = image.image[h][0][w];
00185           imgBuffer[3*(h*lineWidth + w) + 2] = image.image[h][1][w];
00186           imgBuffer[3*(h*lineWidth + w) + 1] = image.image[h][2][w];
00187         }
00188       file.write(imgBuffer,3*image.cameraInfo.resolutionWidth*image.cameraInfo.resolutionHeight);
00189     }
00190     delete [] imgBuffer;
00191     stop();
00192     return true;
00193   }
00194   stop();
00195   return false;
00196 }
00197 
00198 void LogPlayer::saveCSVrow(OutTextRawFile& file, double* row, unsigned int rowLen)
00199 {
00200   if (fabs(row[0])<=1e10)
00201   {
00202     file << row[0];
00203     for (unsigned int i=1;i<rowLen;i++)
00204     {
00205       if (fabs(row[i])>1e10)
00206       {
00207         file << ", -";
00208       }
00209       else
00210       {
00211         file << ", " << row[i];
00212       }
00213       row[i]=1e11;
00214     }
00215     file << "\n";
00216   }
00217 }
00218 
00219 bool LogPlayer::saveCSV(const char* fileName)
00220 {
00221   //add more data to row if you like:
00222   static const unsigned int rowLen=7;
00223   if (getNumberOfMessages() == 0) return false;
00224   OutTextRawFile file(fileName);
00225   if (file.exists())
00226   {
00227     double row[rowLen];
00228     for (int i=1;i<rowLen;i++)
00229     {
00230       row[i]=1e11;
00231     }
00232     file << "frame, specialPercept.checkerPose.x, specialPercept.checkerPose.y, specialPercept.checkerPose.r, robotPose.x, robotPose.y, robotPose.r\n";
00233     for (currentMessageNumber=0; currentMessageNumber<getNumberOfMessages();currentMessageNumber++)
00234     {
00235       queue.setSelectedMessageForReading(currentMessageNumber);
00236       switch (getCurrentMessageID())
00237       {
00238       case idSpecialPercept:
00239         {
00240           Player pl;
00241           CameraMatrix cm;
00242           SpecialPercept specialPercept;
00243           in.bin >> pl >> specialPercept >> cm;
00244           if (specialPercept.type==SpecialPercept::checkerboard)
00245           {
00246             if (specialPercept.frameNumber!=row[0])
00247             {
00248               saveCSVrow(file, row, rowLen);
00249               row[0]=specialPercept.frameNumber;
00250             }
00251             row[1]=specialPercept.checkerPose.translation.x;
00252             row[2]=specialPercept.checkerPose.translation.y;
00253             row[3]=specialPercept.checkerPose.rotation;
00254           }
00255         }
00256         break;
00257       case idWorldState:
00258         {
00259           RobotPose robotPose;
00260           BallModel ballModel;
00261           PlayerPoseCollection playerPoseCollection;
00262           ObstaclesModel obstaclesModel;
00263           RobotState robotState;
00264           CameraMatrix cameraMatrix;
00265           CameraInfo cameraInfo;
00266           in.bin >> RECEIVE_WORLDSTATE(robotPose,ballModel,playerPoseCollection,
00267             obstaclesModel,robotState,cameraMatrix,cameraInfo);
00268           if (robotPose.frameNumber!=row[0])
00269           {
00270             saveCSVrow(file, row, rowLen);
00271             row[0]=robotPose.frameNumber;
00272           }
00273           row[4]=robotPose.translation.x;
00274           row[5]=robotPose.translation.y;
00275           row[6]=robotPose.rotation;
00276         }
00277         break;
00278       default:
00279         continue;
00280       }
00281     }
00282     saveCSVrow(file, row, rowLen);
00283     stop();
00284     return true;
00285   }
00286   stop();
00287   return false;
00288 }
00289 
00290 bool LogPlayer::saveImages(const char* fileName)
00291 {
00292   struct BmpHeader{
00293     unsigned long k0,k1,k2;
00294     unsigned long ofs1,ofs2;
00295     unsigned long xsiz,ysiz;
00296     unsigned long modbit;
00297     unsigned long z1;
00298     unsigned long len;
00299     unsigned long z2,z3,z4,z5;
00300   } bmpHeader;
00301   
00302   char name[512];
00303   char fname[512];
00304   strcpy(name,fileName);
00305   if ((strlen(name)>4)&&((strncmp(name+strlen(name)-4,".bmp",4)==0)||(strncmp(name+strlen(name)-4,".jpg",4)==0)))
00306   {
00307     *(name+strlen(name)-4) = 0;
00308   }
00309   if ((strlen(name)>4)&&((strncmp(name+strlen(name)-4,"_000",4)==0)||(strncmp(name+strlen(name)-4,"_001",4)==0)))
00310   {
00311     *(name+strlen(name)-4) = 0;
00312   }
00313   int i=0;
00314   for (currentMessageNumber=0; currentMessageNumber<getNumberOfMessages();currentMessageNumber++)
00315   {
00316     CameraMatrix cameraMatrix;
00317     queue.setSelectedMessageForReading(currentMessageNumber);
00318     Image image;
00319     if (getCurrentMessageID()==idImage)
00320     {
00321       in.bin >> image >> cameraMatrix;
00322     }
00323     else if (getCurrentMessageID()==idJPEGImage)
00324     {
00325       JPEGImage jpegImage;
00326       in.bin >> jpegImage >> cameraMatrix;
00327       jpegImage.toImage(image);
00328     }
00329     else
00330       continue;
00331 
00332     Image rgbImage;
00333     rgbImage.convertFromYUVToRGB(image);
00334 
00335     sprintf(fname,"%s_%03i.bmp",name,i++);
00336     OutBinaryFile file(fname);
00337     if (file.exists())
00338     {
00339       long truelinelength=(3*rgbImage.cameraInfo.resolutionWidth+3) & 0xfffffc;
00340       char line[3*208+4];
00341       memset(line,0,truelinelength);
00342       bmpHeader.k0=0x4d420000;    //2 dummy bytes 4 alignment, then "BM"
00343       bmpHeader.k1=rgbImage.cameraInfo.resolutionHeight*truelinelength+0x36;
00344       bmpHeader.k2=0;
00345       bmpHeader.ofs1=0x36;
00346       bmpHeader.ofs2=0x28;
00347       bmpHeader.xsiz=rgbImage.cameraInfo.resolutionWidth;
00348       bmpHeader.ysiz=rgbImage.cameraInfo.resolutionHeight;
00349       bmpHeader.modbit=0x00180001;
00350       bmpHeader.z1=0;
00351       bmpHeader.len=truelinelength*rgbImage.cameraInfo.resolutionHeight;
00352       bmpHeader.z2=0;
00353       bmpHeader.z3=0;
00354       bmpHeader.z4=0;
00355       bmpHeader.z5=0;
00356       file.write(2+(char*)&bmpHeader,sizeof(bmpHeader)-2);
00357       for (int i=rgbImage.cameraInfo.resolutionHeight-1; i>=0; i--)
00358       {
00359         int ofs=0;
00360         for (int j=0;j<rgbImage.cameraInfo.resolutionWidth;j++)
00361         {
00362           line[ofs++]=rgbImage.image[i][2][j];
00363           line[ofs++]=rgbImage.image[i][1][j];
00364           line[ofs++]=rgbImage.image[i][0][j];
00365         }
00366         file.write(line,truelinelength);
00367       }
00368     }
00369     else
00370     {
00371       stop();
00372       return false;
00373     }
00374   }
00375   stop();
00376   return true;
00377 }
00378 
00379 void LogPlayer::record()
00380 {
00381   switch(state)
00382   {
00383   case recording:
00384     pause();
00385     break;
00386   case paused:
00387   case initial:
00388   case playing:
00389     state = recording;
00390     break;
00391   }
00392 }
00393 
00394 void LogPlayer::smooth()
00395 {
00396   if(smoothingEnabled)
00397     smoothingEnabled = false;
00398   else 
00399     smoothingEnabled = true;
00400 }
00401 
00402 void LogPlayer::setPlaySpeed(double speed)
00403 {
00404   playSpeed = speed;
00405   timeWhenFirstMessageWasPlayed = 0;
00406 }
00407 
00408 void LogPlayer::handleMessage(InMessage& message)
00409 {
00410   if (state == recording)
00411     message >> *this;
00412 }
00413 
00414 LogPlayer::LogPlayerState LogPlayer::getState()
00415 {
00416   return state;
00417 }
00418 
00419 void LogPlayer::onIdle()
00420 {
00421   if (state == playing)
00422   {
00423     while (1)
00424     {
00425       if (currentMessageNumber < getNumberOfMessages()-1)
00426       {
00427         if (timeWhenFirstMessageWasPlayed == 0 ||
00428             (double)(int(getTimeStamp(currentMessageNumber+1)) - int(timeOfFirstPlayedMessage))
00429             > (double)(SystemCall::getTimeSince(timeWhenFirstMessageWasPlayed)) * playSpeed + 4000)
00430         {
00431           copyMessage(++currentMessageNumber,targetQueue);
00432           timeOfFirstPlayedMessage = getTimeStamp(currentMessageNumber);
00433           timeWhenFirstMessageWasPlayed = SystemCall::getCurrentSystemTime();
00434         }
00435         else
00436         {
00437           if ((double)(int(getTimeStamp(currentMessageNumber+1)) - int(timeOfFirstPlayedMessage))
00438             < (double)(SystemCall::getTimeSince(timeWhenFirstMessageWasPlayed)) * playSpeed)
00439           {
00440             copyMessage(++currentMessageNumber,targetQueue);
00441           }
00442           else
00443           {
00444             break;
00445           }
00446         }
00447       }
00448       else 
00449       {  
00450         stop();
00451         break;
00452       }
00453     }
00454   }
00455 }
00456 
00457 unsigned long LogPlayer::getTimeStamp(int message)
00458 {
00459   return queue.getTimeStamp(message);
00460 }
00461 
00462 int LogPlayer::getNumberOfMessages() const
00463 {
00464   return queue.getNumberOfMessages();
00465 }
00466 
00467 int LogPlayer::getCurrentMessageNumber() const
00468 {
00469   return currentMessageNumber;
00470 }
00471 
00472 MessageID LogPlayer::getCurrentMessageID() const
00473 {
00474   if(currentMessageNumber <= 0) return undefined;
00475   return queue.getMessageID();
00476 }
00477 
00478 /*
00479 * Change Log:
00480 *
00481 * $Log: LogPlayer.cpp,v $
00482 * Revision 1.1.1.1  2004/05/22 17:37:17  cvsadm
00483 * created new repository GT2004_WM
00484 *
00485 * Revision 1.10  2004/05/19 07:58:14  dueffert
00486 * saving to CSV implemented
00487 *
00488 * Revision 1.9  2004/04/20 13:18:08  roefer
00489 * LogPlayer immediately switches to next message if it is older than 4 seconds (instead of one second).
00490 *
00491 * Revision 1.8  2004/03/26 16:33:57  thomas
00492 * added field in logplayer to jump directly to a given frame-number
00493 *
00494 * Revision 1.7  2004/03/24 12:55:42  risler
00495 * added logplayer repeat button
00496 *
00497 * Revision 1.6  2004/02/16 12:26:41  nistico
00498 * Added noise reduction functionality for jpeg images in log file player
00499 *
00500 * Revision 1.5  2004/02/10 16:34:39  nistico
00501 * Fixed bug with ERS-7 log files saved (converted) as a series of .bmp images
00502 *
00503 * Revision 1.4  2004/01/20 12:40:09  nistico
00504 * - Added support for ColorTable32K (65K elements in packed format)
00505 * - RobotControl can now convert GT *.log files into AIBOVision (external ColorTable32K calibration tool) *.amv file format
00506 *
00507 * Revision 1.3  2003/12/15 11:49:06  juengel
00508 * Introduced CameraInfo
00509 *
00510 * Revision 1.2  2003/12/02 10:42:30  lohmann
00511 * WorldstatePlayer Dialog changes
00512 *
00513 * Revision 1.1  2003/10/07 10:13:24  cvsadm
00514 * Created GT2004 (M.J.)
00515 *
00516 * Revision 1.2  2003/09/26 15:28:10  juengel
00517 * Renamed DataTypes to representations.
00518 *
00519 * Revision 1.1.1.1  2003/07/02 09:40:28  cvsadm
00520 * created new repository for the competitions in Padova from the 
00521 * tamara CVS (Tuesday 2:00 pm)
00522 *
00523 * removed unused solutions
00524 *
00525 * Revision 1.7  2003/05/03 21:57:47  roefer
00526 * Skip large pauses
00527 *
00528 * Revision 1.6  2002/12/17 15:50:49  dueffert
00529 * support for writing idJPEGImage to *.bmp added
00530 *
00531 * Revision 1.5  2002/12/15 23:34:13  dueffert
00532 * saving images from logfiles added
00533 *
00534 * Revision 1.4  2002/12/07 16:40:45  roefer
00535 * Blocking for theDebugReceiver changed
00536 *
00537 * Revision 1.3  2002/10/04 10:27:33  loetzsch
00538 * Added functionality to adjust the speed of playing log files.
00539 *
00540 * Revision 1.2  2002/10/02 15:50:41  juengel
00541 * Added getCurrentMessageID.
00542 *
00543 * Revision 1.1  2002/09/10 15:53:59  cvsadm
00544 * Created new project GT2003 (M.L.)
00545 * - Cleaned up the /Src/DataTypes directory
00546 * - Removed challenge related source code
00547 * - Removed processing of incoming audio data
00548 * - Renamed AcousticMessage to SoundRequest
00549 *
00550 * Revision 1.1  2002/08/08 16:40:30  loetzsch
00551 * added class LogPlayer and redesigned RobotControl's Logplayer GUI
00552 *
00553 */

Generated on Thu Sep 23 19:57:39 2004 for GT2004 by doxygen 1.3.6