00001 #ifndef Impala_Core_VideoSet_Walker_h
00002 #define Impala_Core_VideoSet_Walker_h
00003
00004 #include <vector>
00005 #include "Persistency/QuidTableRepository.h"
00006 #include "Persistency/SegmentationRepository.h"
00007 #include "Persistency/KeyframesRepository.h"
00008 #include "Persistency/AnnotationTableRepository.h"
00009 #include "Basis/ConfigBase.h"
00010 #include "Core/Table/AnnotationTable.h"
00011 #include "Core/VideoSet/VideoSet.h"
00012 #include "Core/VideoSet/Segmentation.h"
00013 #include "Core/VideoSet/RgbDataSrcKeyframes.h"
00014 #include "Core/VideoSet/Listener.h"
00015 #include "Core/Geometry/DatabaseReadVxRectangle.h"
00016 #include "Util/DatabaseReadString.h"
00017 #include "Util/Database.h"
00018 #include "Util/IOBuffer.h"
00019
00020 namespace Impala
00021 {
00022 namespace Core
00023 {
00024 namespace VideoSet
00025 {
00026
00027 class WalkerConfig : public ConfigBase
00028 {
00029 public:
00030 WalkerConfig()
00031 {
00032 iFrames = false;
00033 keyframeSrc = false;
00034 partialWalk = false;
00035 virtualWalk = false;
00036 maxKeyframeMask = -1;
00037 numberFrames = -1;
00038 numberKeyframes = -1;
00039 numberQuids = -1;
00040 startKeyframe = 0;
00041 startQuid = 0;
00042 stepSize = 1;
00043 }
00044
00045 void InitOptions(CmdOptions& co)
00046 {
00047 co.AddOption(0, "iFrames", "", "false");
00048 co.AddOption(0, "keyframeSrc", "", "false");
00049 co.AddOption(0, "virtualWalk", "", "false");
00050 co.AddOption(0, "partialWalk", "", "false");
00051
00052 co.AddOption(0, "numberFrames", "nr", "-1");
00053 co.AddOption(0, "numberKeyframes", "nr", "-1");
00054 co.AddOption(0, "numberQuids", "nr", "-1");
00055 co.AddOption(0, "startKeyframe", "idx", "0");
00056 co.AddOption(0, "startQuid", "idx", "0");
00057 co.AddOption(0, "stepSize", "nr", "1");
00058 }
00059
00060 void RetrieveOptions(CmdOptions& co)
00061 {
00062 iFrames = co.GetBool("iFrames", iFrames);
00063 keyframeSrc = co.GetBool("keyframeSrc", keyframeSrc);
00064 partialWalk = co.GetBool("partialWalk", partialWalk);
00065 virtualWalk = co.GetBool("virtualWalk", virtualWalk);
00066 maxKeyframeMask = co.GetInt("maxKeyframeMask", maxKeyframeMask);
00067 numberFrames = co.GetInt("numberFrames", numberFrames);
00068 numberKeyframes = co.GetInt("numberKeyframes", numberKeyframes);
00069 numberQuids = co.GetInt("numberQuids", numberQuids);
00070 startKeyframe = co.GetInt("startKeyframe", startKeyframe);
00071 startQuid = co.GetInt("startQuid", startQuid);
00072 stepSize = co.GetInt("stepSize", stepSize);
00073 }
00074
00075 private:
00076 bool iFrames;
00077 bool keyframeSrc;
00078 bool partialWalk;
00079 bool virtualWalk;
00080 int maxKeyframeMask;
00081 int numberFrames;
00082 int numberKeyframes;
00083 int numberQuids;
00084 int startKeyframe;
00085 int startQuid;
00086 int stepSize;
00087
00088 friend class Walker;
00089 };
00090
00091
00092
00093 class Walker
00094 {
00095 public:
00096
00097 Walker(VideoSet* videoSet, WalkerConfig config) : mConfig(config)
00098 {
00099 mVideoSet = videoSet;
00100 mSegmentation = 0;
00101 mKeyframes = 0;
00102 mKeyframeMask = 0;
00103 mQuids = new Table::QuidTable(0);
00104 }
00105
00106 virtual
00107 ~Walker()
00108 {
00109 for(int i = 0; i < mListeners.size(); i++)
00110 {
00111 delete mListeners[i];
00112 }
00113 mListeners.clear();
00114 }
00115
00116 void
00117 AddListener(Listener* listener)
00118 {
00119 mListeners.push_back(listener);
00120 }
00121
00122 int
00123 NrListeners() const
00124 {
00125 return mListeners.size();
00126 }
00127
00128 void
00129 LoadSegmentation(String name)
00130 {
00131 if (mSegmentation)
00132 delete mSegmentation;
00133 Persistency::SegmentationLocator loc(mVideoSet->GetLocator(), name);
00134 mSegmentation = Persistency::SegmentationRepository().Get(loc,
00135 mVideoSet);
00136 }
00137
00138 Segmentation*
00139 GetSegmentation()
00140 {
00141 return mSegmentation;
00142 }
00143
00144 void
00145 LoadKeyframes(String name)
00146 {
00147 if (mKeyframes)
00148 delete mKeyframes;
00149 Persistency::KeyframesLocator loc(mVideoSet->GetLocator(), name);
00150 mKeyframes = Persistency::KeyframesRepository().Get(loc, mVideoSet);
00151 }
00152
00153 Keyframes*
00154 GetKeyframes()
00155 {
00156 return mKeyframes;
00157 }
00158
00159 void
00160 SetKeyframeMask(bool* mask)
00161 {
00162 mKeyframeMask = mask;
00163 }
00164
00165 void
00166 AddRkfMask()
00167 {
00168 if (!InitKeyframeMask())
00169 return;
00170 int nrKey = mKeyframes->GetNrKeyframes();
00171 for (int i=0 ; i<nrKey ; i++)
00172 mKeyframeMask[i] &= mKeyframes->IsRKF(i);
00173 }
00174
00175 void
00176 AddKeyframeMaskAnnoFile(String fileName)
00177 {
00178 if (!InitKeyframeMask())
00179 return;
00180 StringList sList(fileName, '/');
00181 if (sList.size() != 4)
00182 ILOG_ERROR("AddKeyframeMaskAnnoFile: expected 4 elements in path");
00183 StringListCI it = sList.begin();
00184 it++;
00185 String quidStr = *it++;
00186 String conceptSet = *it++;
00187 String keyword = FileNameBase(*it);
00188 Persistency::AnnotationTableLocator loc(mVideoSet->GetLocator(),
00189 StringToQuidClass(quidStr),
00190 conceptSet, keyword);
00191 Table::AnnotationTable* annoTable =
00192 Persistency::AnnotationTableRepository().Get(loc);
00193 int nrKey = mKeyframes->GetNrKeyframes();
00194 for (int i=0 ; i<nrKey ; i++)
00195 {
00196 Quid quid = mKeyframes->GetQuidFrame(i);
00197 bool present = annoTable->IsPositive(quid);
00198 mKeyframeMask[i] &= present;
00199 }
00200 delete annoTable;
00201 }
00202
00203 bool*
00204 GetKeyframeMask()
00205 {
00206 return mKeyframeMask;
00207 }
00208
00209 void
00210 LoadQuids(String fileName)
00211 {
00212 Persistency::QuidTableLocator loc(mVideoSet->GetLocator(),
00213 FileNamePath(fileName),
00214 FileNameTail(fileName));
00215 mQuids = Persistency::QuidTableRepository().Get(loc);
00216 mQuidWalkName = FileNameBase(fileName);
00217 mQuids->UpdateGroups();
00218 }
00219
00220 Core::Table::QuidTable*
00221 GetQuids()
00222 {
00223 return mQuids;
00224 }
00225
00226 void
00227 LoadBookmarks(String fileName)
00228 {
00229 mVrList.clear();
00230 Persistency::FileLocator loc(mVideoSet->GetLocator(), fileName);
00231 Geometry::DatabaseReadVxRectangle(std::back_inserter(mVrList), loc);
00232 }
00233
00234 int
00235 TotalNrFramesInBookmarks()
00236 {
00237 int nr = 0;
00238 for (size_t i=0 ; i<mVrList.size() ; i++)
00239 {
00240 Geometry::VxRectangle vr = mVrList[i];
00241 nr += vr.mEndFrame - vr.mStartFrame + 1;
00242 }
00243 return nr;
00244 }
00245
00246
00247
00248 void
00249 DoWalk()
00250 {
00251 DoWalk(0, mVideoSet->NrFiles(), 0);
00252 }
00253
00254 void
00255 DoWalk(int startFile, int numberFiles, int startFrame)
00256 {
00257 if (startFile >= mVideoSet->NrFiles())
00258 {
00259 ILOG_ERROR("DoWalk: startFile out of range");
00260 return;
00261 }
00262 if (numberFiles == -1)
00263 numberFiles = mVideoSet->NrFiles() - startFile;
00264 if (startFile + numberFiles >= mVideoSet->NrFiles())
00265 numberFiles = mVideoSet->NrFiles() - startFile;
00266
00267 for (size_t l=0 ; l<mListeners.size() ; l++)
00268 {
00269 mListeners[l]->HandleNewWalk(mVideoSet);
00270 mListeners[l]->HandleNewWalk(mVideoSet, "Frames");
00271 if (mSegmentation)
00272 mListeners[l]->HandleNewWalk(mVideoSet, mSegmentation);
00273
00274 if (mConfig.partialWalk)
00275 mListeners[l]->HandleNewWalkPartial(mVideoSet, startFrame,
00276 mConfig.stepSize,
00277 mConfig.numberFrames);
00278 }
00279
00280 for (int fileId=startFile ; fileId<startFile+numberFiles ; fileId++)
00281 {
00282 if (mConfig.virtualWalk)
00283 {
00284 for (size_t l=0 ; l<mListeners.size() ; l++)
00285 mListeners[l]->HandleNewFile(mVideoSet, fileId, 0);
00286 for (size_t l=0 ; l<mListeners.size() ; l++)
00287 mListeners[l]->HandleDoneFile(mVideoSet, fileId, 0);
00288 continue;
00289 }
00290
00291 Stream::RgbDataSrc* src = mVideoSet->GetVideo(fileId);
00292 if (src == 0)
00293 {
00294 ILOG_ERROR("DoWalk: Failed on file: " +
00295 mVideoSet->GetAsPath(fileId));
00296 continue;
00297 }
00298
00299 for (size_t l=0 ; l<mListeners.size() ; l++)
00300 mListeners[l]->HandleNewFile(mVideoSet, fileId, src);
00301
00302 if (!src->GotoFrame(startFrame))
00303 {
00304 ILOG_ERROR("DoWalk: Failed on src->GotoFrame() for file: " +
00305 mVideoSet->GetAsPath(fileId));
00306 delete src;
00307 src = 0;
00308 }
00309
00310 if (src && mConfig.iFrames)
00311 {
00312 while (!src->CurIsIFrame() && !src->TheEnd())
00313 {
00314 if (!src->NextFrame(mConfig.stepSize))
00315 {
00316 ILOG_ERROR("DoWalk: Failed on src->NextFrame() for file: " +
00317 mVideoSet->GetAsPath(fileId));
00318 delete src;
00319 src = 0;
00320 break;
00321 }
00322 }
00323 }
00324
00325 if (src && src->TheEnd())
00326 ILOG_ERROR("DoWalk: no IFrames found");
00327
00328 int lastShot = -1;
00329 int numberFrames = mConfig.numberFrames;
00330 bool done = false;
00331 do
00332 {
00333 if (!src)
00334 break;
00335
00336 if (mSegmentation)
00337 {
00338 int frame = src->FrameNr();
00339 int shot = mSegmentation->GetShotId(fileId, frame);
00340 if (shot != lastShot)
00341 {
00342 if (lastShot != -1)
00343 for (size_t l=0 ; l<mListeners.size() ; l++)
00344 mListeners[l]->HandleDoneShot(mVideoSet, fileId,
00345 src, lastShot);
00346 for (size_t l=0 ; l<mListeners.size() ; l++)
00347 mListeners[l]->HandleNewShot(mVideoSet, fileId,
00348 src, shot);
00349 lastShot = shot;
00350 }
00351 }
00352
00353 for (size_t l=0 ; l<mListeners.size() ; l++)
00354 mListeners[l]->HandleNewFrame(mVideoSet, fileId, src);
00355
00356 if (mConfig.stepSize == 10000000)
00357 {
00358 done = true;
00359 }
00360 else
00361 {
00362
00363
00364 try
00365 {
00366 src->NextFrame(mConfig.stepSize);
00367 if (mConfig.iFrames)
00368 {
00369 while (!src->CurIsIFrame() && !src->TheEnd())
00370 src->NextFrame(mConfig.stepSize);
00371 }
00372 }
00373 catch (std::exception& e)
00374 {
00375 String eMsg(e.what());
00376 ILOG_ERROR("DoWalk: Failed on src->NextFrame() for file: "
00377 + mVideoSet->GetAsPath(fileId) + ": " + eMsg);
00378 delete src;
00379 src = 0;
00380 break;
00381 }
00382 }
00383
00384 if (src->TheEnd())
00385 done = true;
00386
00387 if (numberFrames > 0)
00388 {
00389 numberFrames--;
00390 if (numberFrames <= 0)
00391 done = true;
00392 }
00393 } while (!done);
00394
00395 if (mSegmentation && (lastShot != -1))
00396 for (size_t l=0 ; l<mListeners.size() ; l++)
00397 mListeners[l]->HandleDoneShot(mVideoSet, fileId, src,
00398 lastShot);
00399
00400 for (size_t l=0 ; l<mListeners.size() ; l++)
00401 mListeners[l]->HandleDoneFile(mVideoSet, fileId, src);
00402
00403 if (src)
00404 delete src;
00405 }
00406
00407 for (size_t l=0 ; l<mListeners.size() ; l++)
00408 mListeners[l]->HandleDoneWalk(mVideoSet);
00409 }
00410
00411 void
00412 DoWalkKeyframes(int startFile, int numberFiles)
00413 {
00414 if (mKeyframes == 0)
00415 {
00416 ILOG_ERROR("DoWalkKeyframes: no keyframes loaded");
00417 return;
00418 }
00419 if (startFile >= mVideoSet->NrFiles())
00420 {
00421 ILOG_ERROR("DoWalkKeyframes: startFile out of range");
00422 return;
00423 }
00424 if (numberFiles == -1)
00425 numberFiles = mVideoSet->NrFiles();
00426 if (startFile + numberFiles >= mVideoSet->NrFiles())
00427 numberFiles = mVideoSet->NrFiles() - startFile;
00428
00429 for (size_t l=0 ; l<mListeners.size() ; l++)
00430 {
00431 mListeners[l]->HandleNewWalk(mVideoSet);
00432 mListeners[l]->HandleNewWalk(mVideoSet, "Keyframes");
00433 mListeners[l]->HandleNewWalk(mVideoSet, mKeyframes, mKeyframeMask);
00434 if (mSegmentation)
00435 mListeners[l]->HandleNewWalk(mVideoSet, mSegmentation);
00436 }
00437 ILOG_DEBUG("fileId range = " << startFile << " - "
00438 << startFile+numberFiles);
00439 for (int fileId=startFile ; fileId<startFile+numberFiles ; fileId++)
00440 {
00441 ILOG_DEBUG("fileId = " << fileId);
00442 ILOG_NDC_PUSH("video " << fileId);
00443 Stream::RgbDataSrc* src = 0;
00444 if (mConfig.keyframeSrc)
00445 src = new RgbDataSrcKeyframes(mVideoSet, mKeyframes, fileId);
00446 else if (!mConfig.virtualWalk)
00447 src = mVideoSet->GetVideo(fileId);
00448 for (size_t l=0 ; l<mListeners.size() ; l++)
00449 mListeners[l]->HandleNewFile(mVideoSet, fileId, src);
00450 int numberKeyframes = mConfig.numberKeyframes;
00451 int startK = mKeyframes->GetFirstKeyframeVideo(fileId);
00452 int numberK = mKeyframes->GetNrKeyframesVideo(fileId);
00453 int lastK = startK + numberK;
00454 ILOG_INFO("keyframes are " << startK << " - " << lastK << " (nr = "
00455 << numberK << ")");
00456 if (mConfig.startKeyframe < numberK)
00457 startK += mConfig.startKeyframe;
00458 if (numberKeyframes == -1)
00459 numberKeyframes = numberK;
00460
00461
00462
00463 bool done = false;
00464 int k = startK;
00465 ILOG_DEBUG("processing " << startK << " - " << lastK << " (max "
00466 << numberKeyframes << ")");
00467 while (!done)
00468 {
00469 if ((!mKeyframeMask) || mKeyframeMask[k])
00470 {
00471 ILOG_DEBUG("keyframe " << k);
00472 if (src)
00473 {
00474 ILOG_DEBUG("GotoFrame " << mKeyframes->GetFrameNr(k));
00475 src->GotoFrame(mKeyframes->GetFrameNr(k));
00476 ILOG_DEBUG("src at " << src->FrameNr());
00477 }
00478 for (size_t l=0 ; l<mListeners.size() ; l++)
00479 mListeners[l]->HandleNewFrame(mVideoSet, fileId, src);
00480 if (--numberKeyframes <= 0)
00481 done = true;
00482 }
00483 if (++k >= lastK)
00484 done = true;
00485 }
00486 for (size_t l=0 ; l<mListeners.size() ; l++)
00487 mListeners[l]->HandleDoneFile(mVideoSet, fileId, src);
00488 if (src)
00489 delete src;
00490 ILOG_NDC_POP;
00491 }
00492
00493 for (size_t l=0 ; l<mListeners.size() ; l++)
00494 mListeners[l]->HandleDoneWalk(mVideoSet);
00495 }
00496
00497 void
00498 DoWalkQuids(int startFile, int numberFiles)
00499 {
00500 if ((mQuids == 0) || (mQuids->Size() == 0))
00501 {
00502 ILOG_ERROR("DoWalkQuids: no quids loaded");
00503 return;
00504 }
00505 if (startFile >= mVideoSet->NrFiles())
00506 {
00507 ILOG_ERROR("DoWalkQuids: startFile out of range");
00508 return;
00509 }
00510 if (numberFiles == -1)
00511 numberFiles = mVideoSet->NrFiles();
00512 if (startFile + numberFiles >= mVideoSet->NrFiles())
00513 numberFiles = mVideoSet->NrFiles() - startFile;
00514
00515 for (size_t l=0 ; l<mListeners.size() ; l++)
00516 {
00517 mListeners[l]->HandleNewWalk(mVideoSet);
00518 mListeners[l]->HandleNewWalk(mVideoSet, mQuidWalkName);
00519 if (mSegmentation)
00520 mListeners[l]->HandleNewWalk(mVideoSet, mSegmentation);
00521 }
00522 ILOG_DEBUG("fileId range = " << startFile << " - "
00523 << startFile+numberFiles);
00524 for (int fileId=startFile ; fileId<startFile+numberFiles ; fileId++)
00525 {
00526 ILOG_DEBUG("fileId = " << fileId);
00527 ILOG_NDC_PUSH("video " << fileId);
00528 int numberQuids = mConfig.numberQuids;
00529 int startQ = mQuids->GetFirstQuidObject(fileId);
00530 int numberQ = mQuids->GetNrQuidsObject(fileId);
00531 if (numberQ == 0)
00532 continue;
00533
00534 int lastQ = startQ + numberQ;
00535 ILOG_INFO("quids are " << startQ << " - " << lastQ << " (nr = "
00536 << numberQ << ")");
00537 if (mConfig.startQuid < numberQ)
00538 startQ += mConfig.startQuid;
00539 if (numberQuids == -1)
00540 numberQuids = numberQ;
00541 bool done = false;
00542 int qIdx = startQ;
00543 ILOG_DEBUG("processing " << startQ << " - " << lastQ << " (max "
00544 << numberQuids << ")");
00545 Stream::RgbDataSrc* src = 0;
00546 if (!mConfig.virtualWalk)
00547 src = mVideoSet->GetVideo(fileId);
00548 for (size_t l=0 ; l<mListeners.size() ; l++)
00549 mListeners[l]->HandleNewFile(mVideoSet, fileId, src);
00550 while (!done)
00551 {
00552 ILOG_DEBUG("quidIdx " << qIdx);
00553 Quid quid = mQuids->Get1(qIdx);
00554 if (src)
00555 {
00556 int frameNr = QuidId(quid);
00557 ILOG_DEBUG("GotoFrame " << frameNr);
00558 src->GotoFrame(frameNr);
00559 ILOG_DEBUG("src at " << src->FrameNr());
00560 }
00561 for (size_t l=0 ; l<mListeners.size() ; l++)
00562 mListeners[l]->HandleNewFrame(mVideoSet, fileId, src);
00563 if (--numberQuids <= 0)
00564 done = true;
00565 if (++qIdx >= lastQ)
00566 done = true;
00567 }
00568 for (size_t l=0 ; l<mListeners.size() ; l++)
00569 mListeners[l]->HandleDoneFile(mVideoSet, fileId, src);
00570 if (src)
00571 delete src;
00572 ILOG_NDC_POP;
00573 }
00574
00575 for (size_t l=0 ; l<mListeners.size() ; l++)
00576 mListeners[l]->HandleDoneWalk(mVideoSet);
00577 }
00578
00579 void
00580 DoWalkBookmarks()
00581 {
00582 for (size_t l=0 ; l<mListeners.size() ; l++)
00583 {
00584 mListeners[l]->HandleNewWalk(mVideoSet, mVrList.size());
00585 mListeners[l]->HandleNewWalk(mVideoSet, "Bookmarks");
00586 }
00587 for (size_t v=0 ; v<mVrList.size() ; v++)
00588 {
00589 ILOG_INFO("Bookmark " << v << " of " << mVrList.size());
00590 Geometry::VxRectangle vr = mVrList[v];
00591 int fileId = mVideoSet->GetFileId(vr.mVideoName);
00592
00593
00594
00595
00596 Stream::RgbDataSrc* src = mVideoSet->GetVideo(fileId);
00597 for (size_t l=0 ; l<mListeners.size() ; l++)
00598 mListeners[l]->HandleNewFile(mVideoSet, fileId, src, v, vr);
00599
00600 Geometry::Rectangle r = vr.mRect;
00601 String s = vr.mAnno;
00602 src->GotoFrame(vr.mStartFrame);
00603 for (size_t l=0 ; l<mListeners.size() ; l++)
00604 mListeners[l]->HandleNewFrame(mVideoSet, fileId, src, r, s);
00605 while (src->FrameNr() < vr.mEndFrame)
00606 {
00607 src->NextFrame();
00608 for (size_t l=0 ; l<mListeners.size() ; l++)
00609 mListeners[l]->HandleNewFrame(mVideoSet, fileId, src, r, s);
00610 }
00611
00612 for (size_t l=0 ; l<mListeners.size() ; l++)
00613 mListeners[l]->HandleDoneFile(mVideoSet, fileId, src, v, vr);
00614 delete src;
00615 }
00616 for (size_t l=0 ; l<mListeners.size() ; l++)
00617 mListeners[l]->HandleDoneWalk(mVideoSet, mVrList.size());
00618 }
00619
00620 protected:
00621
00622 bool
00623 InitKeyframeMask()
00624 {
00625 if (mKeyframes == 0)
00626 {
00627 ILOG_ERROR("InitKeyframeMask: no keyframes loaded");
00628 return false;
00629 }
00630 if (mKeyframeMask)
00631 return true;
00632 int nrKey = mKeyframes->GetNrKeyframes();
00633 mKeyframeMask = new bool[nrKey];
00634 for (int i=0 ; i<nrKey ; i++)
00635 mKeyframeMask[i] = true;
00636 return true;
00637 }
00638
00639 VideoSet* mVideoSet;
00640 Segmentation* mSegmentation;
00641 Keyframes* mKeyframes;
00642 Core::Table::QuidTable* mQuids;
00643 String mQuidWalkName;
00644 std::vector<Geometry::VxRectangle> mVrList;
00645 std::vector<Listener*> mListeners;
00646 bool* mKeyframeMask;
00647 WalkerConfig mConfig;
00648
00649 ILOG_VAR_DEC;
00650 };
00651
00652 ILOG_VAR_INIT(Walker, Impala.Core.VideoSet);
00653
00654 }
00655 }
00656 }
00657
00658 #endif