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

Generated on Fri Mar 19 09:31:19 2010 for ImpalaSrc by  doxygen 1.5.1