00001
00002
00003
00004
00005
00006
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 #include "Platform/GTAssert.h"
00021
00022 LogPlayer::LogPlayer(MessageQueue& targetQueue)
00023 : targetQueue(targetQueue),
00024 smoothingEnabled(false),
00025 playSpeed(1)
00026 {
00027 _new();
00028 }
00029
00030 void LogPlayer::_new()
00031 {
00032 clear();
00033 stop();
00034 state = initial;
00035 }
00036
00037 bool LogPlayer::open(const char* fileName)
00038 {
00039 InBinaryFile file(fileName);
00040 if (file.exists())
00041 {
00042 clear();
00043 file >> *this;
00044 stop();
00045 return true;
00046 }
00047 return false;
00048 }
00049
00050 void LogPlayer::play()
00051 {
00052 pause();
00053 state = playing;
00054 }
00055
00056 void LogPlayer::stop()
00057 {
00058 pause();
00059 currentMessageNumber = -1;
00060 }
00061
00062 void LogPlayer::pause()
00063 {
00064 if (getNumberOfMessages() == 0) state = initial;
00065 else state = paused;
00066
00067 timeOfFirstPlayedMessage = 0;
00068 timeWhenFirstMessageWasPlayed = 0;
00069 }
00070
00071 void LogPlayer::stepBackward()
00072 {
00073 pause();
00074
00075 if (state == paused && currentMessageNumber > 0 )
00076 copyMessage(--currentMessageNumber,targetQueue);
00077 }
00078
00079 void LogPlayer::stepForward()
00080 {
00081 pause();
00082
00083 if ((state == paused) && (currentMessageNumber < getNumberOfMessages()-1))
00084 copyMessage(++currentMessageNumber,targetQueue);
00085 }
00086
00087 void LogPlayer::stepRepeat()
00088 {
00089 pause();
00090
00091 if (state == paused && currentMessageNumber >= 0 )
00092 copyMessage(currentMessageNumber,targetQueue);
00093 }
00094
00095 void LogPlayer::jumpFrame(int frame)
00096 {
00097 pause();
00098
00099 if (state == paused && frame >= 1 && frame <= getNumberOfMessages() )
00100 copyMessage(currentMessageNumber = frame - 1,targetQueue);
00101 }
00102
00103 bool LogPlayer::save(const char* fileName)
00104 {
00105 if (getNumberOfMessages() == 0) return false;
00106
00107 OutBinaryFile file(fileName);
00108 if (file.exists())
00109 {
00110 file << *this;
00111 return true;
00112 }
00113 return false;
00114 }
00115
00116
00117 void LogPlayer::convertIntString(char* str, int value)
00118 {
00119 char temp[256];
00120 int i=0;
00121 while(value > 0)
00122 {
00123 temp[i] = (char)(value % 10) + 48;
00124 value = value / 10; i++;
00125 }
00126 for (int j=i-1; j>=0; j--)
00127 str[j] = temp[i-j-1];
00128 str[i] = '\0';
00129 }
00130
00131 bool LogPlayer::saveAMV(const char* fileName)
00132 {
00133 if (getNumberOfMessages() == 0) return false;
00134 OutBinaryFile file(fileName);
00135 if (file.exists())
00136 {
00137 unsigned char* imgBuffer;
00138 CameraMatrix cameraMatrix;
00139 Image image;
00140 bool headerGenerated = false;
00141 for (currentMessageNumber=0; currentMessageNumber<getNumberOfMessages();currentMessageNumber++)
00142 {
00143 queue.setSelectedMessageForReading(currentMessageNumber);
00144 if (getCurrentMessageID()==idImage)
00145 {
00146 in.bin >> image >> cameraMatrix;
00147 }
00148 else if (getCurrentMessageID()==idJPEGImage)
00149 {
00150 JPEGImage jpegImage;
00151 in.bin >> jpegImage >> cameraMatrix;
00152 jpegImage.toImage(image);
00153 }
00154 else
00155 continue;
00156 if (!headerGenerated){
00157 char* magicNumber = "AIBOMOVIE";
00158 unsigned char padding = 0;
00159 unsigned char magicNumberLenUTF = 9;
00160 file << padding << magicNumberLenUTF;
00161 for (int k=0; k<magicNumberLenUTF; k++)
00162 file << magicNumber[k];
00163 char widthStr[10];
00164 char heightStr[10];
00165 unsigned char widthLenUTF = 3;
00166 unsigned char heightLenUTF = 3;
00167 convertIntString(widthStr, image.cameraInfo.resolutionWidth);
00168 convertIntString(heightStr, image.cameraInfo.resolutionHeight);
00169 file << padding << widthLenUTF;
00170 for (k=0; k<widthLenUTF; k++)
00171 file << widthStr[k];
00172 file << padding << heightLenUTF;
00173 for (k=0; k<heightLenUTF; k++)
00174 file << heightStr[k];
00175 char movType = '0';
00176 unsigned char movTypeLenUTF = 1;
00177 file << padding << movTypeLenUTF << movType;
00178 imgBuffer = new unsigned char[3*image.cameraInfo.resolutionWidth*image.cameraInfo.resolutionHeight];
00179 headerGenerated = true;
00180 }
00181 int lineWidth = image.cameraInfo.resolutionWidth;
00182 for (int h=0; h<image.cameraInfo.resolutionHeight; h++)
00183 for (int w=0; w<image.cameraInfo.resolutionWidth; w++)
00184 {
00185 imgBuffer[3*(h*lineWidth + w) + 0] = image.image[h][0][w];
00186 imgBuffer[3*(h*lineWidth + w) + 2] = image.image[h][1][w];
00187 imgBuffer[3*(h*lineWidth + w) + 1] = image.image[h][2][w];
00188 }
00189 file.write(imgBuffer,3*image.cameraInfo.resolutionWidth*image.cameraInfo.resolutionHeight);
00190 }
00191 delete [] imgBuffer;
00192 stop();
00193 return true;
00194 }
00195 stop();
00196 return false;
00197 }
00198
00199 void LogPlayer::saveCSVrow(OutTextRawFile& file, double* row, unsigned int rowLen)
00200 {
00201 if (fabs(row[0])<=1e10)
00202 {
00203 file << row[0];
00204 for (unsigned int i=1;i<rowLen;i++)
00205 {
00206 if (fabs(row[i])>1e10)
00207 {
00208 file << ", -";
00209 }
00210 else
00211 {
00212 file << ", " << row[i];
00213 }
00214 row[i]=1e11;
00215 }
00216 file << "\n";
00217 }
00218 }
00219
00220 bool LogPlayer::saveCSV(const char* fileName)
00221 {
00222
00223 static const unsigned int rowLen=12;
00224 if (getNumberOfMessages() == 0) return false;
00225 OutTextRawFile file(fileName);
00226 if (file.exists())
00227 {
00228 double row[rowLen];
00229 for (int i=1;i<rowLen;i++)
00230 {
00231 row[i]=1e11;
00232 }
00233 file << "frame, specialPercept.checkerPose.x, specialPercept.checkerPose.y, specialPercept.checkerPose.r, robotPose.x, robotPose.y, robotPose.r, rP.timestamp, rC.x, rC.y, rC.r, rC.timestamp\n";
00234 for (currentMessageNumber=0; currentMessageNumber<getNumberOfMessages();currentMessageNumber++)
00235 {
00236 queue.setSelectedMessageForReading(currentMessageNumber);
00237 switch (getCurrentMessageID())
00238 {
00239 case idSpecialPercept:
00240 {
00241 Player pl;
00242 CameraMatrix cm;
00243 SpecialPercept specialPercept;
00244 in.bin >> pl >> specialPercept >> cm;
00245 if (specialPercept.type==SpecialPercept::checkerboard)
00246 {
00247 if (specialPercept.frameNumber!=row[0])
00248 {
00249 saveCSVrow(file, row, rowLen);
00250 row[0]=specialPercept.frameNumber;
00251 }
00252 row[1]=specialPercept.checkerPose.translation.x;
00253 row[2]=specialPercept.checkerPose.translation.y;
00254 row[3]=specialPercept.checkerPose.rotation;
00255 }
00256 }
00257 break;
00258 case idWorldState:
00259 {
00260 RobotPose robotPose;
00261 BallModel ballModel;
00262 PlayerPoseCollection playerPoseCollection;
00263 ObstaclesModel obstaclesModel;
00264 RobotState robotState;
00265 CameraMatrix cameraMatrix;
00266 CameraInfo cameraInfo;
00267 in.bin >> RECEIVE_WORLDSTATE(robotPose,ballModel,playerPoseCollection,
00268 obstaclesModel,robotState,cameraMatrix,cameraInfo);
00269 if (robotPose.frameNumber!=row[0])
00270 {
00271 saveCSVrow(file, row, rowLen);
00272 row[0]=robotPose.frameNumber;
00273 }
00274 row[4]=robotPose.translation.x;
00275 row[5]=robotPose.translation.y;
00276 row[6]=robotPose.rotation;
00277 row[7]=robotPose.timestamp;
00278 }
00279 break;
00280 case idRemoteCamWorldState:
00281 {
00282 RobotPose robotPose;
00283 BallModel ballModel;
00284 PlayerPoseCollection playerPoseCollection;
00285 ObstaclesModel obstaclesModel;
00286 RobotState robotState;
00287 CameraMatrix cameraMatrix;
00288 CameraInfo cameraInfo;
00289 in.bin >> RECEIVE_WORLDSTATE(robotPose,ballModel,playerPoseCollection,
00290 obstaclesModel,robotState,cameraMatrix,cameraInfo);
00291 row[8]=robotPose.translation.x;
00292 row[9]=robotPose.translation.y;
00293 row[10]=robotPose.rotation;
00294 row[11]=robotPose.timestamp;
00295 }
00296 break;
00297 default:
00298 continue;
00299 }
00300 }
00301 saveCSVrow(file, row, rowLen);
00302 stop();
00303 return true;
00304 }
00305 stop();
00306 return false;
00307 }
00308
00309 bool LogPlayer::saveSynchronized(const char* fileName)
00310 {
00311 MessageQueue nirvana;
00312 LogPlayer remoteCamQueue(nirvana), robotQueue(nirvana);
00313
00314 unsigned long syncTimestampRemoteCam, timestampOfSyncTimestampRemoteCam, syncTimestampRobot;
00315 bool foundSyncTimestampRemoteCam=false;
00316 bool foundSyncTimestampRobot=false;
00317
00318 unsigned long robotSyncMessageTimestamp, remoteCamSyncMessageTimestamp;
00319
00320 for (currentMessageNumber=0; currentMessageNumber<getNumberOfMessages();currentMessageNumber++)
00321 {
00322 queue.setSelectedMessageForReading(currentMessageNumber);
00323 switch (getCurrentMessageID())
00324 {
00325
00326 case idRemoteCamWorldState:
00327 copyMessage(currentMessageNumber,remoteCamQueue);
00328 break;
00329
00330 case idSyncTimestampRemoteCam:
00331 remoteCamSyncMessageTimestamp=queue.getTimeStamp();
00332 in.bin>>syncTimestampRemoteCam>>timestampOfSyncTimestampRemoteCam;
00333 remoteCamSyncMessageTimestamp -= timestampOfSyncTimestampRemoteCam - syncTimestampRemoteCam;
00334 foundSyncTimestampRemoteCam=true;
00335 break;
00336
00337 case idSyncTimestampRobot:
00338 robotSyncMessageTimestamp=queue.getTimeStamp();
00339 in.bin>>syncTimestampRobot;
00340 foundSyncTimestampRobot=true;
00341 break;
00342
00343 default:
00344 copyMessage(currentMessageNumber,robotQueue);
00345 break;
00346 }
00347 }
00348
00349 if (!(foundSyncTimestampRobot&&foundSyncTimestampRemoteCam)) return false;
00350
00351
00352
00353 long messageOffset= robotSyncMessageTimestamp - remoteCamSyncMessageTimestamp;
00354 long offset= syncTimestampRobot - syncTimestampRemoteCam;
00355
00356 int robotQueueCurrentMessageNumber=0;
00357 int remoteCamQueueCurrentMessageNumber=0;
00358
00359
00360 LogPlayer saveQueue(nirvana);
00361
00362 while (robotQueue.queue.getNumberOfMessages()>robotQueueCurrentMessageNumber&&remoteCamQueue.queue.getNumberOfMessages()>remoteCamQueueCurrentMessageNumber)
00363 {
00364 remoteCamQueue.queue.setSelectedMessageForReading(remoteCamQueueCurrentMessageNumber);
00365 robotQueue.queue.setSelectedMessageForReading(robotQueueCurrentMessageNumber);
00366
00367 if (robotQueue.queue.getTimeStamp()<remoteCamQueue.queue.getTimeStamp()+messageOffset)
00368 {
00369 robotQueue.copyMessage(robotQueueCurrentMessageNumber,saveQueue);
00370 robotQueueCurrentMessageNumber++;
00371 } else {
00372
00373
00374 RobotPose robotPose;
00375 BallModel ballModel;
00376 PlayerPoseCollection playerPoseCollection;
00377 ObstaclesModel obstaclesModel;
00378 RobotState robotState;
00379 CameraMatrix cameraMatrix;
00380 CameraInfo cameraInfo;
00381
00382 remoteCamQueue.in.bin >> RECEIVE_WORLDSTATE(robotPose,ballModel,playerPoseCollection,obstaclesModel,robotState, cameraMatrix, cameraInfo);
00383
00384 if (((double)robotPose.timestamp + (double)offset >= 0.0) && (robotPose.getValidity() != 0.0))
00385 {
00386 unsigned long newTimestamp = robotPose.timestamp + offset;
00387
00388 robotPose.setTimestamp(newTimestamp);
00389 robotPose.setFrameNumber(newTimestamp);
00390 ballModel.seen.timeWhenLastSeen = newTimestamp;
00391 ballModel.setFrameNumber(newTimestamp);
00392
00393 PlayerPose playerPose;
00394 int i;
00395 for(i = 0; i < playerPoseCollection.numberOfOwnPlayers; ++i)
00396 {
00397 playerPose = playerPoseCollection.getOwnPlayerPose(i);
00398 playerPose.setFrameNumber(newTimestamp);
00399 playerPoseCollection.setOwnPlayerPose(i, playerPose);
00400 }
00401 for(i = 0; i < playerPoseCollection.numberOfOpponentPlayers; ++i)
00402 {
00403 playerPose = playerPoseCollection.getOpponentPlayerPose(i);
00404 playerPose.setFrameNumber(newTimestamp);
00405 playerPoseCollection.setOpponentPlayerPose(i, playerPose);
00406 }
00407
00408 saveQueue.out.bin << SEND_WORLD_STATE(robotPose,ballModel,playerPoseCollection,obstaclesModel,robotState, cameraMatrix, cameraInfo);
00409 saveQueue.out.finishMessage(
00410 remoteCamQueue.queue.getMessageID(),
00411 remoteCamQueue.queue.getTimeStamp()+messageOffset,
00412 remoteCamQueue.queue.getTeamColor(),
00413 remoteCamQueue.queue.getPlayerNumber(),
00414 remoteCamQueue.queue.getMessageWasSentFromAPhysicalRobot());
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 }
00425 remoteCamQueueCurrentMessageNumber++;
00426 }
00427 }
00428
00429 while (robotQueue.queue.getNumberOfMessages()>robotQueueCurrentMessageNumber)
00430 {
00431 robotQueue.copyMessage(robotQueueCurrentMessageNumber,saveQueue);
00432 robotQueueCurrentMessageNumber++;
00433 }
00434
00435 while (remoteCamQueue.queue.getNumberOfMessages()>remoteCamQueueCurrentMessageNumber)
00436 {
00437
00438 saveQueue.out.bin.write(remoteCamQueue.queue.getData(),remoteCamQueue.queue.getMessageSize());
00439 saveQueue.out.finishMessage(
00440 remoteCamQueue.queue.getMessageID(),
00441 remoteCamQueue.queue.getTimeStamp()+messageOffset,
00442 remoteCamQueue.queue.getTeamColor(),
00443 remoteCamQueue.queue.getPlayerNumber(),
00444 remoteCamQueue.queue.getMessageWasSentFromAPhysicalRobot());
00445
00446 remoteCamQueueCurrentMessageNumber++;
00447 }
00448
00449 return saveQueue.save(fileName);
00450
00451 return false;
00452 }
00453
00454 bool LogPlayer::saveImages(const char* fileName)
00455 {
00456 struct BmpHeader{
00457 unsigned long k0,k1,k2;
00458 unsigned long ofs1,ofs2;
00459 unsigned long xsiz,ysiz;
00460 unsigned long modbit;
00461 unsigned long z1;
00462 unsigned long len;
00463 unsigned long z2,z3,z4,z5;
00464 } bmpHeader;
00465
00466 char name[512];
00467 char fname[512];
00468 strcpy(name,fileName);
00469 if ((strlen(name)>4)&&((strncmp(name+strlen(name)-4,".bmp",4)==0)||(strncmp(name+strlen(name)-4,".jpg",4)==0)))
00470 {
00471 *(name+strlen(name)-4) = 0;
00472 }
00473 if ((strlen(name)>4)&&((strncmp(name+strlen(name)-4,"_000",4)==0)||(strncmp(name+strlen(name)-4,"_001",4)==0)))
00474 {
00475 *(name+strlen(name)-4) = 0;
00476 }
00477 int i=0;
00478 for (currentMessageNumber=0; currentMessageNumber<getNumberOfMessages();currentMessageNumber++)
00479 {
00480 CameraMatrix cameraMatrix;
00481 queue.setSelectedMessageForReading(currentMessageNumber);
00482 Image image;
00483 if (getCurrentMessageID()==idImage)
00484 {
00485 in.bin >> image >> cameraMatrix;
00486 }
00487 else if (getCurrentMessageID()==idJPEGImage)
00488 {
00489 JPEGImage jpegImage;
00490 in.bin >> jpegImage >> cameraMatrix;
00491 jpegImage.toImage(image);
00492 }
00493 else
00494 continue;
00495
00496 Image rgbImage;
00497 rgbImage.convertFromYCbCrToRGB(image);
00498
00499 sprintf(fname,"%s_%03i.bmp",name,i++);
00500 OutBinaryFile file(fname);
00501 if (file.exists())
00502 {
00503 long truelinelength=(3*rgbImage.cameraInfo.resolutionWidth+3) & 0xfffffc;
00504 char line[3*208+4];
00505 memset(line,0,truelinelength);
00506 bmpHeader.k0=0x4d420000;
00507 bmpHeader.k1=rgbImage.cameraInfo.resolutionHeight*truelinelength+0x36;
00508 bmpHeader.k2=0;
00509 bmpHeader.ofs1=0x36;
00510 bmpHeader.ofs2=0x28;
00511 bmpHeader.xsiz=rgbImage.cameraInfo.resolutionWidth;
00512 bmpHeader.ysiz=rgbImage.cameraInfo.resolutionHeight;
00513 bmpHeader.modbit=0x00180001;
00514 bmpHeader.z1=0;
00515 bmpHeader.len=truelinelength*rgbImage.cameraInfo.resolutionHeight;
00516 bmpHeader.z2=0;
00517 bmpHeader.z3=0;
00518 bmpHeader.z4=0;
00519 bmpHeader.z5=0;
00520 file.write(2+(char*)&bmpHeader,sizeof(bmpHeader)-2);
00521 for (int i=rgbImage.cameraInfo.resolutionHeight-1; i>=0; i--)
00522 {
00523 int ofs=0;
00524 for (int j=0;j<rgbImage.cameraInfo.resolutionWidth;j++)
00525 {
00526 line[ofs++]=rgbImage.image[i][2][j];
00527 line[ofs++]=rgbImage.image[i][1][j];
00528 line[ofs++]=rgbImage.image[i][0][j];
00529 }
00530 file.write(line,truelinelength);
00531 }
00532 }
00533 else
00534 {
00535 stop();
00536 return false;
00537 }
00538 }
00539 stop();
00540 return true;
00541 }
00542
00543 void LogPlayer::record()
00544 {
00545 switch(state)
00546 {
00547 case recording:
00548 pause();
00549 break;
00550 case paused:
00551 case initial:
00552 case playing:
00553 state = recording;
00554 break;
00555 }
00556 }
00557
00558 void LogPlayer::smooth()
00559 {
00560 if(smoothingEnabled)
00561 smoothingEnabled = false;
00562 else
00563 smoothingEnabled = true;
00564 }
00565
00566 void LogPlayer::setPlaySpeed(double speed)
00567 {
00568 playSpeed = speed;
00569 timeWhenFirstMessageWasPlayed = 0;
00570 }
00571
00572 void LogPlayer::handleMessage(InMessage& message)
00573 {
00574 if (state == recording)
00575 message >> *this;
00576 }
00577
00578 LogPlayer::LogPlayerState LogPlayer::getState()
00579 {
00580 return state;
00581 }
00582
00583 void LogPlayer::onIdle()
00584 {
00585 if (state == playing)
00586 {
00587 while (1)
00588 {
00589 if (currentMessageNumber < getNumberOfMessages()-1)
00590 {
00591 if (timeWhenFirstMessageWasPlayed == 0 ||
00592 (double)(int(getTimeStamp(currentMessageNumber+1)) - int(timeOfFirstPlayedMessage))
00593 > (double)(SystemCall::getTimeSince(timeWhenFirstMessageWasPlayed)) * playSpeed + 4000)
00594 {
00595 copyMessage(++currentMessageNumber,targetQueue);
00596 timeOfFirstPlayedMessage = getTimeStamp(currentMessageNumber);
00597 timeWhenFirstMessageWasPlayed = SystemCall::getCurrentSystemTime();
00598 }
00599 else
00600 {
00601 if ((double)(int(getTimeStamp(currentMessageNumber+1)) - int(timeOfFirstPlayedMessage))
00602 < (double)(SystemCall::getTimeSince(timeWhenFirstMessageWasPlayed)) * playSpeed)
00603 {
00604 copyMessage(++currentMessageNumber,targetQueue);
00605 }
00606 else
00607 {
00608 targetQueue.removeRepetitions();
00609 break;
00610 }
00611 }
00612 }
00613 else
00614 {
00615 stop();
00616 break;
00617 }
00618 }
00619 }
00620 }
00621
00622 unsigned long LogPlayer::getTimeStamp(int message)
00623 {
00624 return queue.getTimeStamp(message);
00625 }
00626
00627 int LogPlayer::getNumberOfMessages() const
00628 {
00629 return queue.getNumberOfMessages();
00630 }
00631
00632 int LogPlayer::getCurrentMessageNumber() const
00633 {
00634 return currentMessageNumber;
00635 }
00636
00637 MessageID LogPlayer::getCurrentMessageID() const
00638 {
00639 if(currentMessageNumber < 0) return undefined;
00640 return queue.getMessageID();
00641 }
00642
00643 void LogPlayer::keep(MessageID* messageIDs)
00644 {
00645 LogPlayer temp((MessageQueue&) *this);
00646 moveAllMessages(temp);
00647 for(temp.currentMessageNumber = 0; temp.currentMessageNumber < temp.getNumberOfMessages(); ++temp.currentMessageNumber)
00648 {
00649 temp.queue.setSelectedMessageForReading(temp.currentMessageNumber);
00650 MessageID* m = messageIDs;
00651 while(*m)
00652 {
00653 if(*m == temp.getCurrentMessageID())
00654 {
00655 temp.stepRepeat();
00656 break;
00657 }
00658 ++m;
00659 }
00660 }
00661 }
00662
00663 void LogPlayer::remove(MessageID* messageIDs)
00664 {
00665 LogPlayer temp((MessageQueue&) *this);
00666 moveAllMessages(temp);
00667 for(temp.currentMessageNumber = 0; temp.currentMessageNumber < temp.getNumberOfMessages(); ++temp.currentMessageNumber)
00668 {
00669 temp.queue.setSelectedMessageForReading(temp.currentMessageNumber);
00670 MessageID* m = messageIDs;
00671 while(*m)
00672 {
00673 if(*m == temp.getCurrentMessageID())
00674 break;
00675 ++m;
00676 }
00677 if(!*m)
00678 temp.stepRepeat();
00679 }
00680 }
00681
00682 void LogPlayer::statistics(int frequency[numOfMessageIDs])
00683 {
00684 int i;
00685 for(i = 0; i < numOfMessageIDs; ++i)
00686 frequency[i] = 0;
00687 for(i = 0; i < getNumberOfMessages(); ++i)
00688 {
00689 queue.setSelectedMessageForReading(i);
00690 ASSERT(queue.getMessageID() < numOfMessageIDs);
00691 ++frequency[queue.getMessageID()];
00692 }
00693 }