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

StrategyIgnoringNativeIndex.h

Go to the documentation of this file.
00001 #ifndef Impala_Core_Stream_Lavc_StrategyIgnoringNativeIndex_h
00002 #define Impala_Core_Stream_Lavc_StrategyIgnoringNativeIndex_h
00003 
00004 #include "Core/Stream/Lavc/VideoAccessStrategy.h"
00005 #include "Core/Stream/Lavc/VideoIndex.h"
00006 
00007 namespace Impala
00008 {
00009 namespace Core
00010 {
00011 namespace Stream
00012 {
00013 namespace Lavc
00014 {
00015 
00016 class StrategyIgnoringNativeIndex : public VideoAccessStrategy
00017 {
00018 
00019 public:
00020 
00021     StrategyIgnoringNativeIndex(const Lavc::VideoAccessObject* const vao) 
00022         : VideoAccessStrategy(vao)
00023     {
00024         ILOG_DEBUG("Applying video access strategy based on " <<
00025             "frame positions expressed in bytes");
00026     }
00027 
00028     virtual bool
00029     FrameCanBeRead(int frameNr) const
00030     {
00031         // all frames' data can be read
00032         return true;
00033     }
00034 
00035 
00036 protected:
00037 
00038     virtual int
00039     GetJumpFlags() const
00040     {
00041         return AVSEEK_FLAG_BYTE;
00042     }
00043 
00044     virtual bool
00045     ScanProtected()
00046     {
00047         ILOG_INFO("First scan pass, collecting...");
00048         bool debug = false;
00049         if (!debug)
00050             ScanPackets(false);
00051         //else
00052         //    ReadScanData("scandata");
00053         //if (!debug)
00054         //    WriteScanData("scandata");
00055         mScanDataPresent = true;
00056         mVao->Reset();
00057         ILOG_INFO("Second scan pass, validating...");
00058         if (!debug)
00059             ScanPackets(true);
00060         //else
00061         //    ReadScanData("scandata");
00062         //if (!debug)
00063         //    WriteScanData("scandata");
00064 
00065         const int frameCnt = mFrames->Size();
00066         if (frameCnt <= 0)
00067         {
00068             ILOG_ERROR("No frames found");
00069             return false;
00070         }
00071 
00072         ILOG_INFO("Detected " << mLeadingBadFrameCount << 
00073             " leading bad frame(s) and " << mBadFrameCount << 
00074             " bad frame(s) in total");
00075         if (mLeadingBadFrameCount >= frameCnt)
00076         {
00077             ILOG_ERROR("No valid frames found");
00078             return false;
00079         }
00080 
00081         const int firstValidFrameNr = mLeadingBadFrameCount;
00082         if (!FrameIsKey(firstValidFrameNr))
00083         {
00084             ILOG_ERROR("Unexpected: first valid frame (" << firstValidFrameNr <<
00085                 ") is not a key frame (type: " << mVao->FrameType() << ")");
00086             return false;
00087         }
00088 
00089         // validate reproduction of first valid key frame's hash
00090         mVao->Reset();
00091         bool lookForKeyFrame = true;
00092         PacketTrace trace(10);
00093         bool foundFirstKeyFrame = 
00094             DecodeNextValidFrame(lookForKeyFrame, &trace);
00095         if (!foundFirstKeyFrame)
00096         {
00097             ILOG_ERROR("Could not locate first valid key frame");
00098             return false;
00099         }
00100 
00101         mVao->CurrentFrameToRgb();
00102         if (!CurrentFrameMatchesFrame(firstValidFrameNr, &trace))
00103         {
00104             ILOG_ERROR("Could not reproduce first valid key frame " << 
00105                 firstValidFrameNr);
00106             return false;
00107         }
00108 
00109         return true;
00110     }
00111 
00117     virtual VideoIndex*
00118     ConstructIndexProtected() const
00119     {
00120         VideoIndex* videoIndex = new VideoIndex();
00121         UInt64 seekPos;
00122         int packetToStartSearchAt = -1; 
00123         const int frameCount = NrOfFrames();
00124         for (int f = 0; f < frameCount; f++)
00125         {
00126             if (FrameIsValid(f) && FrameIsKey(f) && FrameIsStable(f))
00127             {
00128                 const bool frameIsSeekable = FindSeekPosition(f, 
00129                     &seekPos, &packetToStartSearchAt);
00130                 if (frameIsSeekable)
00131                 {
00132                     videoIndex->AddFrame(f, true, seekPos);
00133                     ILOG_DEBUG("Indexed frame: " << f << " " << f << 
00134                         " true " << seekPos);
00135                 }
00136                 else if (videoIndex->NrOfEntries() == 0)
00137                 {
00138                     ILOG_ERROR("Failed to find a seek position for " <<
00139                         "frame " << f);
00140                     delete videoIndex;
00141                     return 0;
00142                 }
00143             }
00144         }
00145         return videoIndex;
00146     }
00147 
00148     virtual bool
00149     NextFrameMatchesFrame(int frameNr, const VideoIndex& videoIndex) const
00150     {
00151         if (!DecodeNextValidFrame(false))
00152         {
00153             ILOG_DEBUG("Failed on sequential read for frame " << frameNr);
00154             return false;
00155         }
00156 
00157         if (FrameIsStable(frameNr))
00158         {
00159             mVao->CurrentFrameToRgb();
00160             if (!CurrentHashMatchesFrame(frameNr))
00161             {
00162                 ILOG_DEBUG("Index error for frame " << frameNr << 
00163                     " ; hash found = " << mVao->CurrentHash());
00164                 return false;
00165             }
00166         }
00167 
00168         return true;
00169     }
00170 
00171 
00172 private:
00173 
00174     void
00175     ScanPackets(bool validating)
00176     {
00177         int packetCount = 0;
00178         int frameCount = 0;
00179         mBadFrameCount = 0;
00180         mLeadingBadFrameCount = 0;
00181 
00182         // ***************************
00183         // SK: for debugging
00184         bool _limitWork4Debugging = false;
00185         int _myMax = -1;
00186         if (_limitWork4Debugging)
00187         {
00188             _myMax = 30;
00189             _myMax *= 1;
00190         }
00191         else
00192         {
00193             _myMax *= 1;
00194         }
00195 
00196         bool noMorePackets = false;
00197         while (!noMorePackets && !(_limitWork4Debugging && frameCount > _myMax))
00198         // ***************************
00199             noMorePackets = ScanOnePacket(&packetCount, &frameCount, validating);
00200 
00201         ILOG_DEBUG("Scanned " << packetCount << " packets, and found " <<
00202             frameCount << " frames");
00203     }
00204 
00205     // Returns 'true' if no packet could be read; 'false' otherwise.
00206     bool
00207     ScanOnePacket(int* packetCount, int* frameCount, bool validating)
00208     {
00209         const int MAX_POST_EOF_FAILURES = Max(15, 2 * mVao->GopSize());
00210         int nrOfConsecutivePostEofFailures = 0;
00211 
00212         while (true)
00213         {
00214             const bool atEofBeforeRead = mVao->AtEof();
00215             const int readPacketResult = mVao->ReadPacket();
00216             if (mVao->AtEof() && !atEofBeforeRead)
00217                 ILOG_DEBUG("Reached end of file");
00218 
00219             const bool readPacketFailed = (readPacketResult < 0);
00220             if (!readPacketFailed)
00221             {
00222                 if (atEofBeforeRead)
00223                 {
00224                     ILOG_DEBUG("A packet was successfully read after " <<
00225                         "reading arrived at end of file");
00226                 }
00227                 const int packetNr = (*packetCount)++;
00228                 ProcessPacket(packetNr, frameCount, validating);
00229                 return false;
00230             }
00231 
00232             ILOG_DEBUG("ReadPacket() failed and returned: " << 
00233                 readPacketResult);
00234 
00235             if (atEofBeforeRead)
00236             {
00237                 if (readPacketFailed)
00238                 {
00239                     nrOfConsecutivePostEofFailures++;
00240                     if (nrOfConsecutivePostEofFailures > MAX_POST_EOF_FAILURES)
00241                     {
00242                         ILOG_DEBUG("Max. nr of consecutive post-EOF " <<
00243                             "read failures reached (" <<
00244                             MAX_POST_EOF_FAILURES << ")");
00245                         return true;
00246                     }
00247                 }
00248                 else 
00249                     nrOfConsecutivePostEofFailures = 0;
00250             }
00251         }
00252     }
00253 
00254     // Evaluates the currently read packet, which must be the result of a 
00255     // successful read operation; otherwise this call might incorrectly 'see'
00256     // a valid packet and frame!
00257     void
00258     ProcessPacket(int packetNr, int* frameCount, bool validating)
00259     {
00260         const int size = mVao->CurrentPacketSize();
00261         const int flags = mVao->CurrentPacketFlags();
00262         const UInt64 posAfterRead = mVao->CurrentFilePosition();
00263 
00264         if (validating)
00265         {
00266             if (mPackets->Get2(packetNr) != size || 
00267                 mPackets->Get3(packetNr) != flags ||
00268                 mPackets->Get4(packetNr) != posAfterRead)
00269             {
00270                 ILOG_ERROR("Packet " << packetNr << " not reproducable");
00271                 return;
00272             }
00273         }
00274         else
00275             mPackets->Add(packetNr, size, flags, posAfterRead);
00276 
00277         if (mVao->CurrentPacketIsVideo()) 
00278         {
00279             int frameDecoded = 0;
00280             const int len = mVao->DecodeFrame(&frameDecoded);
00281 
00282             // libavcodec's packet flags usage is not clear,  
00283             // but this appeared to work out fine: 
00284             const bool ignorePacket = (frameDecoded <= 0) && (flags != 0);
00285 
00286             if (!ignorePacket)
00287             {
00288                 const bool frameValid = (len >= 0 && frameDecoded > 0);
00289                 bool frameIsKey = false;
00290                 if (frameValid)
00291                 {
00292                     frameIsKey = (mVao->FrameType() == 'I' && mVao->FrameIsKey());
00293                 }
00294                 else
00295                 {
00296                     ILOG_DEBUG("DecodeFrame() failed (" << frameDecoded << 
00297                         ") and returned: " << len );
00298                     mBadFrameCount++;
00299                     if (mBadFrameCount >= *frameCount)
00300                         mLeadingBadFrameCount++;
00301                 }
00302 
00303                 const int frameNr = (*frameCount)++;
00304                 ProcessFrame(frameValid, frameIsKey, frameNr, validating);
00305             }
00306         }
00307     }
00308 
00309     // Returns 'true' if a position was found that allows 
00310     // random (seek) access to the specified frame; 'false' otherwise.
00311     // The frame specified must be valid and be a key frame, must not yet occur 
00312     // in the index, and must be greater than all frame nrs already occurring 
00313     // in the index. 
00314     // Furthermore the packet table is assumed to be in ascending 
00315     // order with regard to post-read file positions.
00316     bool
00317     FindSeekPosition(int frameNr, UInt64* seekPos, int* refPacket) const
00318     {
00319         // find: the first next file position suitable for seeking the frame
00320         bool foundCandSeekPos = FindCandidateSeekPosition(seekPos, refPacket);
00321         if (!foundCandSeekPos || !IsValidSeekTarget(frameNr, *seekPos))
00322         {
00323             ILOG_DEBUG("No valid seek position found for frame " << frameNr);
00324             return false;
00325         }
00326 
00327         // optimize: check whether the next candidate position is also valid
00328         UInt64 nextSeekTarget;
00329         int tempRefPacket = *refPacket;
00330         while (true)
00331         {
00332             foundCandSeekPos = 
00333                 FindCandidateSeekPosition(&nextSeekTarget, &tempRefPacket);
00334             if (!foundCandSeekPos || !IsValidSeekTarget(frameNr, nextSeekTarget))
00335                 break;
00336             *seekPos = nextSeekTarget;
00337             *refPacket = tempRefPacket;
00338         }
00339         return true;
00340     }
00341 
00342     // Determines the smallest post-read file position occurring in the packet 
00343     // table from the specified reference packet on, updates the reference 
00344     // packet with the first next packet nr with a post-read position greater than 
00345     // the value found, and returns 'true'. If a negative value is passed in 
00346     // for the ref packet, the first data position from the video 
00347     // stream will be used. If no valid file position could be found, 'false' 
00348     // is returned.
00349     bool FindCandidateSeekPosition(UInt64* seekPos, int* refPacket) const
00350     {
00351         const int packetTableSize = mPackets->Size();
00352         if (*refPacket >= packetTableSize)
00353             return false;
00354 
00355         int nextRefPacket;
00356         if (*refPacket < 0)
00357         {
00358             *seekPos = mVao->FirstPacketPosition();
00359             nextRefPacket = 0;
00360         }
00361         else
00362         {
00363             *seekPos = mPackets->Get4(*refPacket);
00364             nextRefPacket = *refPacket + 1;
00365         }
00366 
00367         while (nextRefPacket < packetTableSize)
00368         {
00369             if (mPackets->Get4(nextRefPacket) > *seekPos) // post-read file pos
00370             {
00371                 *refPacket = nextRefPacket;
00372                 return true;
00373             }
00374             nextRefPacket++;
00375         }
00376 
00377         return false;
00378     }
00379 
00380     // Returns 'true' if seeking to the specified position in the video and 
00381     // reading frames until a key frame is found, will result in the specified
00382     // key frame;
00383     // assumes the specified frame is a valid and stable key frame!
00384     bool
00385     IsValidSeekTarget(int frameNr, const UInt64& seekPos) const
00386     {
00387         PacketTrace trace(10);
00388         static const bool MUST_BE_KEY = true;
00389         if (!Jump(seekPos, AVSEEK_FLAG_BYTE, MUST_BE_KEY, 2, &trace))
00390             return false;
00391 
00392         CurrentFrameToRgb();
00393         if (!CurrentFrameMatchesFrame(frameNr, &trace))
00394             return false;
00395 
00396         UInt64 postReadPos = mPackets->Get4(mFrames->Get2(frameNr));
00397         UInt64 lastPostReadPosOfTrace = trace.Get3(trace.Size() - 1);
00398         if (lastPostReadPosOfTrace <= postReadPos)
00399             return true;
00400 
00401         for (int f = frameNr + 1; f < mFrames->Size(); f++)
00402         {
00403             if (!DecodeNextValidFrame(false, &trace))
00404             {
00405                 ILOG_ERROR("Unexpected: could not find/decode frame " << f);
00406                 return false;
00407             }
00408 
00409             CurrentFrameToRgb();
00410             if (!CurrentFrameMatchesFrame(f, &trace))
00411             {
00412                 ILOG_DEBUG(seekPos << " is not a valid seek target for " <<
00413                     "frame " << frameNr << ", following from a mismatch for " <<
00414                     "frame " << f);
00415                 return false;
00416             }
00417 
00418             postReadPos = mPackets->Get4(mFrames->Get2(f));
00419             lastPostReadPosOfTrace = trace.Get3(trace.Size() - 1);
00420             if (lastPostReadPosOfTrace <= postReadPos)
00421                 break;
00422         }
00423         return true;
00424     }
00425 
00426 
00427     ILOG_VAR_DECL;
00428 
00429 }; //class
00430 
00431 ILOG_VAR_INIT(StrategyIgnoringNativeIndex, Impala.Core.Stream.Lavc);
00432 
00433 }}}} // namespace Impala::Core::Stream::Lavc
00434 
00435 #endif

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