Home || Visual Search || Applications || Architecture || Important Messages || OGL || Src

RgbDataSrcLavc.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Stream_RgbDataSrcLavc_h
00002 #define Impala_Core_Stream_RgbDataSrcLavc_h
00003 
00004 #include "Basis/CmdOptions.h"
00005 #include "Util/Database.h"
00006 
00007 #include "Core/Stream/RgbDataSrcInfo.h"
00008 
00009 #include "Core/Stream/LavcProtocolDataServer.h"
00010 
00011 #include "Core/Stream/Lavc/VideoAccessStrategyFactory.h"
00012 #include "Core/Stream/Lavc/VideoAccessStrategy.h"
00013 #include "Core/Stream/Lavc/VideoIndex.h"
00014 
00015 namespace Impala
00016 {
00017 namespace Core
00018 {
00019 namespace Stream
00020 {
00021 
00027 class RgbDataSrcLavc : public RgbDataSrcInfo
00028 {
00029 
00030     typedef Array::Array2dVec3UInt8 Array2dVec3UInt8;
00031 
00032 public:
00033 
00034 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00035     RgbDataSrcLavc(int src, CString srcName, Util::Database* db, 
00036         IndexMode mode)
00037         : RgbDataSrcInfo(src, srcName, db, 
00038             DetermineInfoName(srcName, mode, db), true)
00039     {
00040 #else // REPOSITORY_USED
00041     RgbDataSrcLavc(int src, const Persistency::RgbDataSrcLocator& loc, 
00042                    IndexMode mode)
00043         : RgbDataSrcInfo(src, loc, "", true)
00044     {
00045         mLoc = loc;
00046         String srcName = loc.GetName();
00047 #endif // REPOSITORY_USED
00048         mSrcName = StringReplaceAll(srcName, "\\", "/", false);
00049         mMode = mode;
00050 
00051         mValid = false;
00052         mBufferedFrameNr = -1;
00053         mLastDecodedFrameNr = -1;
00054 
00055         mFixCnt = 0;
00056         mLastFixNr = 0;
00057 
00058         mVideoAccessor = 0;
00059 
00060         Init();
00061     }
00062 
00063     virtual
00064     ~RgbDataSrcLavc() 
00065     {
00066         if (mVideoAccessor != 0)
00067             delete mVideoAccessor;
00068     }
00069     
00070     virtual char
00071     FrameType() const
00072     {
00073         return mVideoAccessor->FrameType();
00074     }
00075 
00076     virtual String 
00077     FrameHashBeforeConversion() const
00078     {
00079         if (FrameValid(FrameNr()))
00080             return mVideoAccessor->CurrentFrameHashBeforeConversion();
00081         else
00082             return INVALID_FRAME_HASH;
00083     }
00084 
00085     virtual bool
00086     CurIsIFrame() const
00087     {
00088         return FrameType() == 'I';
00089     }
00090 
00091     virtual bool
00092     Valid() const
00093     {
00094         return mValid; 
00095     }
00096 
00097 
00098 protected:
00099 
00100     virtual String
00101     CalcHash() const
00102     {
00103         return mVideoAccessor->CurrentFrameHash();
00104     }
00105 
00106 
00107 private:
00108 
00109     bool
00110     IncurExtraLavcInitialization()
00111     {
00112         Reset();
00113         const int firstValidFrame = LeadingBadFrames();
00114         if (!SeekFrame(firstValidFrame))
00115             return false;
00116         mLastDecodedFrameNr = mBufferedFrameNr = mCurrentFrameNr = firstValidFrame;
00117         return true;
00118     }
00119 
00120     bool
00121     ReadIndex(bool silent)
00122     {
00123         const int currentFrameCount = mLastFrame + 1;
00124         const int currentBadFramesCount = BadFrames();
00125         const int currentLeadingBadCount = LeadingBadFrames();
00126         const bool wasRead = ReadInfo(silent);
00127 
00128         //if (wasRead)
00129         //{
00130         //    // do some sanity checks:
00131         //    if (mLastFrame != currentFrameCount - 1)
00132         //    {
00133         //        ILOG_ERROR("Number of frames according to info file (" << 
00134         //            (mLastFrame + 1) << ") does not match previously " <<
00135         //            " established value (" << currentFrameCount << ")");
00136         //        return false;
00137         //    }
00138         //    if (BadFrames() != currentBadFramesCount)
00139         //    {
00140         //        ILOG_ERROR("Number of bad frames according to " <<
00141         //            "info file (" << LeadingBadFrames() << ") does not match " <<
00142         //            "previously established value (" << 
00143         //            currentBadFramesCount << ")")
00144         //        return false;
00145         //    }
00146         //    if (LeadingBadFrames() != currentLeadingBadCount)
00147         //    {
00148         //        ILOG_ERROR("Number of leading bad frames according to " <<
00149         //            "info file (" << LeadingBadFrames() << ") does not match " <<
00150         //            "previously established value (" << 
00151         //            currentLeadingBadCount << ")")
00152         //        return false;
00153         //    }
00154         //}
00155         return wasRead;
00156     }
00157 
00158     bool
00159     SeekFrame(int seekableFrame)
00160     {
00161         const UInt64 targetPos = GetPos(seekableFrame);
00162         ILOG_DEBUG("Seeking frame " << seekableFrame << " at position " << 
00163             targetPos);
00164         if (!mVideoAccessor->JumpToFramePosition(targetPos))
00165         {
00166             ILOG_ERROR("Jump to frame position "  << targetPos << " failed");
00167             return false;
00168         }
00169         return true;
00170     }
00171 
00172     void
00173     Init()
00174     {
00175         CmdOptions& options = CmdOptions::GetInstance();
00176 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00177         String dataServer = options.GetString("dataServer");
00178 #else // REPOSITORY_USED
00179         String dataServer = (mLoc.GetProtocol() == "dataServer") ? "dataserver"
00180                                                                  : "";
00181 #endif // REPOSITORY_USED
00182         const String dataSrcAddress =
00183             dataServer.empty() ? mSrcName : "dataserver:" + mSrcName;
00184         Lavc::VideoAccessStrategyFactory factory;
00185         mVideoAccessor = factory.Construct(dataSrcAddress);
00186         if (mVideoAccessor == 0)
00187         {
00188             mValid = false;
00189             return;
00190         }
00191 
00192         if (mVideoAccessor->NrOfFrames() >= 0)
00193             mLastFrame = mVideoAccessor->NrOfFrames() - 1;
00194 
00195         InitStaticMetadata(*mVideoAccessor);
00196 
00197         mData = mVideoAccessor->RgbDataPtr();
00198 
00199         if (mMode == SCANONLY)
00200         {
00201             if (!Scan(*mVideoAccessor))
00202                 return;
00203         }
00204         else if (mMode == READIDX)
00205         {
00206             int nrOfFramesNow = -1;
00207             bool checkFrameCount = options.GetBool("checkstoredframecount", false);
00208             if (checkFrameCount)
00209             {
00210                 if (!Scan(*mVideoAccessor))
00211                     return;
00212                 nrOfFramesNow = mVideoAccessor->NrOfFrames();
00213             }
00214 
00215             if (ReadIndex(false))
00216             {
00217                 if (!IncurExtraLavcInitialization())
00218                     return;
00219                 if (checkFrameCount && (nrOfFramesNow != (LastFrame() + 1)))
00220                 {
00221                     ILOG_ERROR("Freshly established frame count (" << 
00222                         nrOfFramesNow << ") different " <<
00223                         "from stored frame count (" << LastFrame() + 1 << 
00224                         ") for: " << mSrcName);
00225                     return;
00226                 }
00227             }
00228             else
00229             {
00230                 ILOG_ERROR("Failed while reading index info for: " << 
00231                     mSrcName);
00232                 return;
00233             }
00234         }
00235         else if (mMode == WITHIDX)
00236         {
00237             if (ReadIndex(true))
00238             {
00239                 if (!IncurExtraLavcInitialization())
00240                     return;
00241             }
00242             else
00243             {
00244                 if (!PopulateIndex(*mVideoAccessor))
00245                     return;
00246             }
00247         }
00248         else if (mMode == ADHOCIDX)
00249         {
00250             if (!PopulateIndex(*mVideoAccessor))
00251                 return;
00252         }
00253         else if (mMode == WRITEIDX)
00254         {
00255             if (!PopulateIndex(*mVideoAccessor))
00256                 return;
00257             WriteInfo();
00258         }
00259 
00260         Reset();
00261         mValid = true;
00262         ILOG_DEBUG("Initialization succeeded");
00263     }
00264 
00265 
00266     void 
00267         InitStaticMetadata(const Lavc::VideoAccessStrategy& videoAccessStrategy)
00268     {
00269         // local scope VAO class usage in order to isolate knowledge
00270         // of this class; using access strategy (sub-) classes is preferred
00271         const Lavc::VideoAccessObject* const vao = 
00272             videoAccessStrategy.VideoAccessObj();
00273 
00274         // collect format info
00275         mBitRate = vao->BitRate();
00276         mFormatName = vao->FormatNameShort();
00277         mFormatLName = vao->FormatNameLong();
00278         ILOG_INFO("Format name is: " << mFormatLName << " (" << 
00279             mFormatName << ")");
00280 
00281         // collect stream info
00282         mStreamCount = vao->StreamCount();
00283         mVideoDuration = vao->VideoDuration();
00284         mTimeBaseNum = vao->VideoTimeBaseNumerator();
00285         mTimeBaseDen = vao->VideoTimeBaseDenominator();
00286         mDuration = ceil(
00287             double(mVideoDuration) * mTimeBaseNum / mTimeBaseDen
00288             ); // rounded up (number of seconds)
00289         mDurationSec = mDuration;
00290         mDurationHour = mDurationSec / 3600;
00291         mDurationSec %= 3600;
00292         mDurationMin = mDurationSec / 60;
00293         mDurationSec %= 60;
00294 
00295         // collect frame info
00296         mFrameRateNum = vao->FrameRateNumerator();
00297         mFrameRateDen = vao->FrameRateDenominator();
00298         const double fractionsPerSec = double(mTimeBaseDen) / mTimeBaseNum;
00299         const double secondsPerFrame = double(mFrameRateDen) / mFrameRateNum;
00300         const double fractionsPerFrame = fractionsPerSec * secondsPerFrame;
00301         const double frameCount = mVideoDuration / fractionsPerFrame;
00302         mFrameCountCalculated = ceil(frameCount);
00303         ILOG_INFO("Frame count estimate based on video duration: " << 
00304             mFrameCountCalculated);
00305 
00306         mFrameWidth = vao->FrameWidth();
00307         mFrameHeight = vao->FrameHeight();
00308         mAspectRatioNum = vao->AspectRatioNum();
00309         mAspectRatioDen = vao->AspectRatioDen();
00310 
00311         mGopSize = vao->GopSize();
00312 
00313         mCodecTag = vao->VideoCodecTag();
00314         mCodecName = vao->VideoCodecName();
00315 
00316         ILOG_INFO("Opened codec (id=" << vao->VideoCodecId() << 
00317             ", name=" << mCodecName << ") for: " << mSrcName);
00318     }
00319 
00320     void 
00321     Reset()
00322     {
00323         mVideoAccessor->ResetVideoSrc();
00324         mLastDecodedFrameNr = mBufferedFrameNr = mCurrentFrameNr = -1;
00325     }
00326 
00327     bool PopulateIndex(Lavc::VideoAccessStrategy& accessStrategy)
00328     {
00329         if (!Scan(accessStrategy))
00330             return false;
00331 
00332         ILOG_INFO("Starting index population...");
00333         ILOG_INFO("Constructing intermediate index...");
00334         Lavc::VideoIndex* tempIndex = accessStrategy.ConstructIndex();
00335         if (!tempIndex)
00336         {
00337             ILOG_ERROR("Construction of intermediate index failed; " <<
00338                 "aborting video population");
00339             return false;
00340         }
00341 
00342         // copy data from temp index to local index
00343         const int nrOfFrames = accessStrategy.NrOfFrames();
00344         String frameHash;
00345         int seekableFrameNr;
00346         UInt64 seekableFramePos = 0;
00347         for (int f = 0; f < nrOfFrames; f++)
00348         {
00349             if (accessStrategy.FrameIsValid(f))
00350             {
00351                 frameHash = accessStrategy.FrameHash(f);
00352                 tempIndex->GetSeekInfo(f, &seekableFrameNr, &seekableFramePos);
00353             }
00354             else
00355             {
00356                 MarkBadFrame(f);
00357                 frameHash = DUMMY_FRAME_HASH;
00358                 seekableFrameNr = -1;
00359                 seekableFramePos = -1;
00360             }
00361 
00362             ILOG_DEBUG("Adding to index: " << f << ", " << seekableFrameNr << 
00363                 ", " << seekableFramePos << ", " << frameHash);
00364             AddIndex(f, seekableFrameNr, seekableFramePos, frameHash);
00365         }
00366 
00367         delete tempIndex;
00368         accessStrategy.CleanUp();
00369         mIndexExists = true;
00370         ILOG_INFO("Finished index population");
00371         return true;
00372     }
00373 
00374     bool
00375     Scan(Lavc::VideoAccessStrategy& accessStrategy)
00376     {
00377         if (!accessStrategy.Scan())
00378         {
00379             ILOG_ERROR("Failed while scanning: " << mSrcName);
00380             return false;
00381         }
00382 
00383         const int frameCnt = accessStrategy.NrOfFrames();
00384         mLastFrame = frameCnt - 1;  // may yet change when using native index??
00385         for (int f = 0; f < frameCnt; f++)
00386             if (!accessStrategy.FrameIsValid(f))
00387                 MarkBadFrame(f);
00388         SetLeadingBadFrames(accessStrategy.LeadingBadFrames());
00389         return true;
00390     }
00391 
00392     virtual bool
00393     ReadFrameData()
00394     {
00395         if (mTargetFrameNr == mCurrentFrameNr)
00396             return true;
00397 
00398         if (!FrameValid(mTargetFrameNr) || mTargetFrameNr == mBufferedFrameNr)
00399         {
00400             mCurrentFrameNr = mTargetFrameNr;
00401             return true;
00402         }
00403 
00404         if (mTargetFrameNr < mBufferedFrameNr)
00405             Reset();
00406 
00407         const bool videoSeekable = mIndexExists;
00408         if (videoSeekable)
00409         {
00410             int sFrameNr = GetSeekableFrame(mTargetFrameNr);
00411             // do not use seek just to get to the next frame
00412             if (mBufferedFrameNr < 0 || sFrameNr > mBufferedFrameNr + 1)
00413             //if (sFrameNr > mBufferedFrameNr + 1)
00414             {
00415                 ILOG_DEBUG("Targeting frame " << mTargetFrameNr << 
00416                     " by first seeking to frame " << sFrameNr);
00417                 if (!SeekFrame(sFrameNr))
00418                     return false;
00419                 mLastDecodedFrameNr = mBufferedFrameNr = mCurrentFrameNr = 
00420                     sFrameNr;
00421             }
00422         }
00423 
00424         const bool lastDecodedFrameValid = ReadToTarget();
00425         mCurrentFrameNr = mLastDecodedFrameNr;
00426         if (lastDecodedFrameValid)
00427         {
00428             int result = mVideoAccessor->CurrentFrameToRgb();
00429             mBufferedFrameNr = mCurrentFrameNr;
00430 
00431             if (mFormatName != "asf") // SK: dirty debug fix
00432                 if (!CheckMD5Hash(mBufferedFrameNr))
00433                 {
00434                     ILOG_ERROR("Frame hash failure going to frame " << 
00435                         mTargetFrameNr);
00436                     return false;
00437                 }
00438         }
00439 
00440         return true;
00441     }
00442 
00443     // Read and decode frames until we reach the target frame
00444     bool
00445     ReadToTarget()
00446     {
00447         bool lastDecodedFrameIsValid = true;
00448         while (mLastDecodedFrameNr < mTargetFrameNr)
00449         {
00450             const int nextFrameNr = mLastDecodedFrameNr + 1;
00451 
00452                         if (mVideoAccessor->FrameCanBeRead(nextFrameNr))
00453                         {
00454                 bool foundValidFrame;
00455                 bool isKeyFrame; // not actually used
00456                 const int decodingResult = mVideoAccessor->
00457                     DecodeNextFrame(&foundValidFrame, &isKeyFrame, 0);
00458                 const bool gotFrame = (decodingResult == 0);
00459                 if (!gotFrame)
00460                 {
00461                     // may occur at eof if the video was not scanned in advance
00462                     if (mLastFrame == LASTFRAME_UNKNOWN)
00463                     {
00464                         mLastFrame = mLastDecodedFrameNr; 
00465                         ILOG_DEBUG("Assuming we arrived at eof; " <<
00466                             "frame count established is: " << mLastFrame + 1);
00467                     }
00468                     return false;
00469                 }
00470                         
00471                 lastDecodedFrameIsValid = FrameValid(nextFrameNr);
00472                 if (lastDecodedFrameIsValid && !foundValidFrame)
00473                 {
00474                     // may occur for bad frames if the video was not scanned in advance
00475                     MarkBadFrame(nextFrameNr);
00476                     lastDecodedFrameIsValid = false;
00477                 }
00478                 else if (!lastDecodedFrameIsValid && foundValidFrame)
00479                 {
00480                     ILOG_WARN("Did not expect to read a valid frame for " << 
00481                         nextFrameNr);
00482                 }
00483                         }
00484             else
00485             {
00486                 if (FrameValid(nextFrameNr))
00487                 {
00488                     // may occur when the video was not scanned in advance
00489                     MarkBadFrame(nextFrameNr);
00490                 }
00491                 lastDecodedFrameIsValid = false;
00492             }
00493 
00494             mLastDecodedFrameNr = nextFrameNr;
00495         }
00496         return lastDecodedFrameIsValid;
00497     }
00498 
00499     bool
00500     CheckMD5Hash(int frameNr) const
00501     {
00502         if (!mIndexExists)
00503             return true;
00504 
00505         if (!FrameIsStable(frameNr))
00506             return true;
00507 
00508         const String refHash = FrameHash(frameNr);
00509         const String hash = CalcHash();
00510         mIsFrameAccurate = (hash == refHash);
00511         if (mIsFrameAccurate)
00512         {
00513             //ILOG_DEBUG("Hash match for frame " << frameNr << ": " << refHash);
00514             return true;
00515         }
00516 
00517         ILOG_ERROR("No hash match for frame " << frameNr << "; expected " <<
00518             refHash << " but found " << hash);
00519         return false;
00520     }
00521 
00522     bool
00523     FrameIsStable(int frameNr) const
00524     {
00525         return FrameHash(frameNr) != mVideoAccessor->UNSTABLE_FRAME_HASH;
00526     }
00527 
00528 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00529     String 
00530     DetermineInfoName(CString srcName, IndexMode mode, Util::Database* db) const
00531     {
00532         String infoName = "";
00533         if (Link::DiskImage::DiskImageUsed())
00534         {
00535             String subPath = FileNamePath(srcName);
00536             if (subPath.substr(0, 10) == "diskimage:")
00537             {
00538                 int posAfterDiskImageFileName = subPath.find("://", 10);
00539                 // SK: assume disk image file name is unique, 
00540                 // not needing an additional (sub-)path specification
00541                 const String uptoDiskImageToken = 
00542                     subPath.substr(0, posAfterDiskImageFileName);
00543                 int diskImageFileNamePos = 
00544                     FileNameLastPathSepPos(uptoDiskImageToken) + 1;
00545                 if (diskImageFileNamePos == String::npos)
00546                     ILOG_ERROR("Disk image file was expected to be prefixed "
00547                     << "with a path: " << uptoDiskImageToken);
00548 
00549                 String subSubPath = 
00550                         subPath.substr(posAfterDiskImageFileName + 1);
00551                 subSubPath = StringReplaceAll(subSubPath,
00552                                                      "0x", "0x30x", false);
00553                 subSubPath = StringReplaceAll(subSubPath, 
00554                                                      "//", "/0x2F", false);
00555                 subSubPath = subSubPath.substr(0, subSubPath.size() - 1);
00556                 subPath = subPath.substr(diskImageFileNamePos, 
00557                     posAfterDiskImageFileName-diskImageFileNamePos)+subSubPath;
00558 
00559                 String dir = "FramePosIndex/" + subPath;
00560 
00561                 bool toWrite = (mode == WRITEIDX);
00562                 bool silent = (mode != READIDX);
00563 
00564                 if (toWrite)
00565                     db->MakeDir(dir);
00566 
00567                 String fname = FileNameTail(srcName) + ".info";
00568                 infoName = db->GetFilePath(dir, fname, toWrite, silent);
00569             }
00570             else
00571                 infoName = srcName + ".info";
00572         }
00573         return infoName;
00574     }
00575 #endif // REPOSITORY_USED
00576 
00577     Lavc::VideoAccessStrategy* mVideoAccessor;
00578     Persistency::RgbDataSrcLocator mLoc;
00579 
00580     int                mBufferedFrameNr; // as RGB frame 
00581     int                mLastDecodedFrameNr;
00582     bool               mValid;
00583     uint32_t           mFrameCountCalculated; // based on mDuration
00584     IndexMode          mMode;
00585 
00586     int                mLastFixNr;
00587     int                mFixCnt;
00588 
00589     ILOG_VAR_DECL;
00590 
00591 }; //class
00592 
00593 ILOG_VAR_INIT(RgbDataSrcLavc, Impala.Core.Stream);
00594 
00595 }}} // namespace Impala::Core::Stream
00596 
00597 #endif

Generated on Thu Jan 13 09:04:36 2011 for ImpalaSrc by  doxygen 1.5.1